Merge remote-tracking branch 'eclipse/master' into remove-ununsed-methods

This commit is contained in:
Kai Zimmermann
2016-01-28 11:42:02 +01:00
38 changed files with 2626 additions and 31 deletions

View File

@@ -12,7 +12,7 @@ mvn install
# Run and use
We are not providing an off the shelf production ready hawkBit server. However, we recommend to check out the [Example Application](examples/hawkbit-example-app) for a runtime ready Spring Boot based server that is empowered by hawkBit.
We are not providing an off the shelf production ready hawkBit server. However, we recommend to check out the [Example Application](examples/hawkbit-example-app) for a runtime ready Spring Boot based update server that is empowered by hawkBit.
# Releases and Roadmap
@@ -20,8 +20,8 @@ We are not providing an off the shelf production ready hawkBit server. However,
* The master branch contains future development towards 0.2. We are currently focusing on:
* Rollout Management for large scale rollouts.
* Clustering capabilities for the update server.
* Upgrade of Spring Boot and Vaadin.
* And of course tones of usability improvements and bug fixes.
* Upgrade of Spring Boot and Vaadin depedencies.
* And of course tons of usability improvements and bug fixes.
## Try out examples
@@ -42,7 +42,7 @@ We are not providing an off the shelf production ready hawkBit server. However,
`hawkbit-http-security` : implementation for security filters for HTTP.
`hawkbit-rest-api` : API classes for the REST Management API.
`hawkbit-rest-resource` : HTTP REST endpoints for the Management and the Direct Device API.
`hawkbit-rest-resource` : Vaadin UI.
`hawkbit-ui` : Vaadin UI.
`hawkbit-cache-redis` : spring cache manager configuration and implementation with redis, distributed cache and distributed events.

View File

@@ -20,6 +20,25 @@ The simulator has user authentication enabled by default. Default credentials:
This can be configured/disabled by spring boot properties
## Usage
### Graphical User Interface
The device simulator comes with a graphical user interface which makes it very easy to generate dummy devices handled by the device simulator.
The status and the update progress of the simulated device are shown in the UI.
The UI can be accessed via the URL:
```
http://localhost:8083
```
`Basic Authentication Credentials are admin / admin`
![](src/main/images/generateScreenshot.png)
![](src/main/images/updateProcessScreenshot.png)
![](src/main/images/updateResultOverviewScreenshot.png)
### REST API
The device simulator exposes an REST-API which can be used to trigger device creation.
Optional parameters:

View File

@@ -80,10 +80,52 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-push</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
<version>8.14.1</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
<version>8.12.1</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId>
<version>7.5.5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -0,0 +1,180 @@
/**
* 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.simulator;
/**
* The bean of a simulated device which can be stored in the
* {@link DeviceSimulatorRepository} or shown in the UI.
*
* @author Michael Hirsch
*
*/
public abstract class AbstractSimulatedDevice {
private String id;
private String tenant;
private Status status;
private double progress;
private String swversion = "unknown";
private ResponseStatus responseStatus = ResponseStatus.SUCCESSFUL;
private Protocol protocol = Protocol.DMF_AMQP;
private int nextPollCounterSec;
/**
* Enum definition of the protocol to be used for the simulated device.
*
* @author Michael Hirsch
*
*/
public enum Protocol {
/**
* Device Management Federation API via AMQP, push mechanism.
*/
DMF_AMQP,
/**
* Direct Device Interface via HTTP, poll mechanism.
*/
DDI_HTTP;
}
/**
* The current status of the simulated device.
*
* @author Michael Hirsch
*
*/
public enum Status {
/**
* device is in status unknown.
*/
UNKNWON,
/**
* device is in status pending which represents is updating software.
*/
PEDNING,
/**
* device has been updated successfully.
*/
FINISH,
/**
* device has been updated with an error.
*/
ERROR;
}
/**
* The status to response to the hawkbit update server if an simulated
* update process should be respond with successful or failure update.
*
* @author Michael Hirsch
*
*/
public enum ResponseStatus {
/**
* updated has been successful and response the successful update.
*/
SUCCESSFUL,
/**
* updated has been not successful and response the error update.
*/
ERROR;
}
/**
* empty constructor.
*/
AbstractSimulatedDevice() {
}
/**
* Creates a new simulated device.
*
* @param id
* the ID of the simulated device
* @param tenant
* the tenant of the simulated device
*/
AbstractSimulatedDevice(final String id, final String tenant, final Protocol protocol) {
this.id = id;
this.tenant = tenant;
this.status = Status.UNKNWON;
this.progress = 0.0;
this.protocol = protocol;
}
/**
* Method to clean-up resource e.g. when the simulated device has been
* removed from the repository.
*/
public void clean() {
}
public String getId() {
return id;
}
public Status getStatus() {
return status;
}
public double getProgress() {
return progress;
}
public String getTenant() {
return tenant;
}
public void setId(final String id) {
this.id = id;
}
public void setTenant(final String tenant) {
this.tenant = tenant;
}
public void setStatus(final Status status) {
this.status = status;
}
public void setProgress(final double progress) {
this.progress = progress;
}
public String getSwversion() {
return swversion;
}
public void setSwversion(final String swversion) {
this.swversion = swversion;
}
public ResponseStatus getResponseStatus() {
return responseStatus;
}
public void setResponseStatus(final ResponseStatus responseStatus) {
this.responseStatus = responseStatus;
}
public Protocol getProtocol() {
return protocol;
}
public int getNextPollCounterSec() {
return nextPollCounterSec;
}
public void setNextPollCounterSec(final int nextPollDelayInSec) {
this.nextPollCounterSec = nextPollDelayInSec;
}
}

View File

@@ -0,0 +1,111 @@
/**
* 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.simulator;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.simulator.DeviceSimulatorUpdater.UpdaterCallback;
import org.eclipse.hawkbit.simulator.http.ControllerResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
/**
* @author Michael Hirsch
*
*/
public class DDISimulatedDevice extends AbstractSimulatedDevice {
private static final Logger LOGGER = LoggerFactory.getLogger(DDISimulatedDevice.class);
private final int pollDelaySec;
private final ScheduledExecutorService pollthreadpool;
private final ControllerResource controllerResource;
private volatile boolean removed;
private volatile Long currentActionId;
private final DeviceSimulatorUpdater deviceUpdater;
/**
* @param id
* the ID of the device
* @param tenant
* the tenant of the simulated device
* @param pollDelaySec
* the delay of the poll interval in sec
* @param controllerResource
* the http controller resource
* @param pollthreadpool
* the threadpool for polling endpoint
* @param deviceUpdater
* the service to update devices
*/
public DDISimulatedDevice(final String id, final String tenant, final int pollDelaySec,
final ControllerResource controllerResource, final ScheduledExecutorService pollthreadpool,
final DeviceSimulatorUpdater deviceUpdater) {
super(id, tenant, Protocol.DDI_HTTP);
this.pollDelaySec = pollDelaySec;
this.controllerResource = controllerResource;
this.pollthreadpool = pollthreadpool;
this.deviceUpdater = deviceUpdater;
setNextPollCounterSec(pollDelaySec);
}
@Override
public void clean() {
super.clean();
removed = true;
}
public int getPollDelaySec() {
return pollDelaySec;
}
/**
* Polls the base URL for the DDI API interface.
*/
public void poll() {
if (!removed) {
final String basePollJson = controllerResource.get(getTenant(), getId());
try {
final String href = JsonPath.parse(basePollJson).read("_links.deploymentBase.href");
final long actionId = Long.parseLong(href.substring(href.lastIndexOf("/") + 1, href.indexOf("?")));
if (currentActionId == null) {
final String deploymentJson = controllerResource.getDeployment(getTenant(), getId(), actionId);
final String swVersion = JsonPath.parse(deploymentJson).read("deployment.chunks[0].version");
currentActionId = actionId;
deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, new UpdaterCallback() {
@Override
public void updateFinished(final AbstractSimulatedDevice device, final Long actionId) {
switch (device.getResponseStatus()) {
case SUCCESSFUL:
controllerResource.postSuccessFeedback(getTenant(), getId(), actionId);
break;
case ERROR:
controllerResource.postErrorFeedback(getTenant(), getId(), actionId);
break;
default:
throw new IllegalStateException("simulated device has an unknown response status + "
+ device.getResponseStatus());
}
currentActionId = null;
}
});
}
} catch (final PathNotFoundException e) {
// href might not be in the json response, so ignore
// exception here.
LOGGER.trace("Response does not contain a deploymentbase href link, ignoring.");
}
}
}
}

View File

@@ -0,0 +1,29 @@
/**
* 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.simulator;
/**
* An simulated device using the DMF API of the hawkbit update server.
*
* @author Michael Hirsch
*
*/
public class DMFSimulatedDevice extends AbstractSimulatedDevice {
/**
* @param id
* the ID of the device
* @param tenant
* the tenant of the simulated device
*/
public DMFSimulatedDevice(final String id, final String tenant) {
super(id, tenant, Protocol.DMF_AMQP);
}
}

View File

@@ -8,8 +8,15 @@
*/
package org.eclipse.hawkbit.simulator;
import java.util.concurrent.Executors;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import com.vaadin.spring.annotation.EnableVaadin;
/**
* The main-method to start the Spring-Boot application.
@@ -18,12 +25,21 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
*
*/
@SpringBootApplication
@EnableVaadin
public class DeviceSimulator {
private DeviceSimulator() {
public DeviceSimulator() {
// utility class
}
/**
* @return an asynchronous event bus to publish and retrieve events.
*/
@Bean
public EventBus eventBus() {
return new AsyncEventBus(Executors.newFixedThreadPool(4));
}
/**
* Start the Spring Boot Application.
*

View File

@@ -0,0 +1,123 @@
/**
* 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.simulator;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* An in-memory simulated device repository to hold the simulated device in
* memory and be able to retrieve them again.
*
* @author Michael Hirsch
*
*/
@Service
public class DeviceSimulatorRepository {
private final Map<DeviceKey, AbstractSimulatedDevice> devices = new LinkedHashMap<>();
@Autowired
private SimulatedDeviceFactory deviceFactory;
/**
* Adds a simulated device to the repository.
*
* @param simulatedDevice
* the device to add
* @return the device which has been added to the repository
*/
public AbstractSimulatedDevice add(final AbstractSimulatedDevice simulatedDevice) {
devices.put(new DeviceKey(simulatedDevice.getTenant().toLowerCase(), simulatedDevice.getId()), simulatedDevice);
return simulatedDevice;
}
/**
* @return all simulated devices
*/
public Collection<AbstractSimulatedDevice> getAll() {
return devices.values();
}
/**
* Retrieves a single simulated devices or {@code null} if device does not
* exists.
*
* @param tenant
* the tenant of the simulated device
* @param id
* the ID of the device
* @return a simulated device from the repository or {@code null} if device
* does not exixts.
*/
public AbstractSimulatedDevice get(final String tenant, final String id) {
return devices.get(new DeviceKey(tenant.toLowerCase(), id));
}
/**
* Clears all stored devices.
*/
public void clear() {
devices.values().forEach(device -> device.clean());
devices.clear();
}
private static final class DeviceKey {
private final String tenant;
private final String id;
private DeviceKey(final String tenant, final String id) {
this.tenant = tenant;
this.id = id;
}
@Override
public int hashCode() {// NOSONAR - as this is generated
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((tenant == null) ? 0 : tenant.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {// NOSONAR - as this is
// generated
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final DeviceKey other = (DeviceKey) obj;
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
if (tenant == null) {
if (other.tenant != null) {
return false;
}
} else if (!tenant.equals(other.tenant)) {
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,122 @@
/**
* 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.simulator;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.eclipse.hawkbit.simulator.event.InitUpdate;
import org.eclipse.hawkbit.simulator.event.ProgressUpdate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.common.eventbus.EventBus;
/**
* @author Michael Hirsch
*
*/
@Service
public class DeviceSimulatorUpdater {
private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(4);
@Autowired
private SpSenderService spSenderService;
@Autowired
private EventBus eventbus;
@Autowired
private DeviceSimulatorRepository repository;
/**
* Starting an simulated update process of an simulated device.
*
* @param tenant
* the tenant of the device
* @param id
* the ID of the simulated device
* @param actionId
* the actionId from the hawkbit update server to start the
* update.
* @param swVersion
* the software module version from the hawkbit update server
* @param callback
* the callback which gets called when the simulated update
* process has been finished
*/
public void startUpdate(final String tenant, final String id, final long actionId, final String swVersion,
final UpdaterCallback callback) {
final AbstractSimulatedDevice device = repository.get(tenant, id);
device.setProgress(0.0);
device.setSwversion(swVersion);
eventbus.post(new InitUpdate(device));
threadPool.schedule(new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback),
2000, TimeUnit.MILLISECONDS);
}
private static final class DeviceSimulatorUpdateThread implements Runnable {
private static final Random rndSleep = new Random();
private final AbstractSimulatedDevice device;
private final SpSenderService spSenderService;
private final long actionId;
private final EventBus eventbus;
private final UpdaterCallback callback;
private DeviceSimulatorUpdateThread(final AbstractSimulatedDevice device,
final SpSenderService spSenderService, final long actionId, final EventBus eventbus,
final UpdaterCallback callback) {
this.device = device;
this.spSenderService = spSenderService;
this.actionId = actionId;
this.eventbus = eventbus;
this.callback = callback;
}
@Override
public void run() {
final double newProgress = device.getProgress() + 0.2;
device.setProgress(newProgress);
if (newProgress < 1.0) {
threadPool.schedule(new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus,
callback), rndSleep.nextInt(3000), TimeUnit.MILLISECONDS);
} else {
callback.updateFinished(device, actionId);
}
eventbus.post(new ProgressUpdate(device));
}
}
/**
* Callback interface which is called when the simulated update process has
* been finished and the caller of starting the simulated update process can
* send the result to the hawkbit update server back.
*
* @author Michael Hirsch
*
*/
@FunctionalInterface
public interface UpdaterCallback {
/**
* Callback method to indicate that the simulated update process has
* been finished.
*
* @param device
* the device which has been updated
* @param actionId
* the ID of the action from the hawkbit update server
*/
void updateFinished(AbstractSimulatedDevice device, final Long actionId);
}
}

View File

@@ -0,0 +1,78 @@
/**
* 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.simulator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.google.common.eventbus.EventBus;
/**
* Poll time trigger which executes the {@link DDISimulatedDevice#poll()} every
* second.
*
* @author Michael Hirsch
*
*/
@Component
public class NextPollTimeController {
private static final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
private static final ExecutorService pollService = Executors.newFixedThreadPool(1);
@Autowired
private DeviceSimulatorRepository repository;
@Autowired
private EventBus eventBus;
/**
* Constructor which schedules the poll trigger runnable every second.
*/
public NextPollTimeController() {
executorService.scheduleWithFixedDelay(new NextPollUpdaterRunnable(), 1, 1, TimeUnit.SECONDS);
}
private class NextPollUpdaterRunnable implements Runnable {
@Override
public void run() {
final List<AbstractSimulatedDevice> devices = repository.getAll().stream()
.filter(device -> device instanceof DDISimulatedDevice).collect(Collectors.toList());
devices.forEach(device -> {
int nextCounter = device.getNextPollCounterSec() - 1;
if (nextCounter < 0) {
if (device instanceof DDISimulatedDevice) {
try {
pollService.submit(new Runnable() {
@Override
public void run() {
((DDISimulatedDevice) device).poll();
}
});
} catch (final Exception e) {
}
nextCounter = ((DDISimulatedDevice) device).getPollDelaySec();
}
}
device.setNextPollCounterSec(nextCounter);
});
eventBus.post(new NextPollCounterUpdate(devices));
}
}
}

View File

@@ -0,0 +1,88 @@
/**
* 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.simulator;
import java.net.URL;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.http.ControllerResource;
import org.eclipse.hawkbit.simulator.http.GatewayTokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import feign.Feign;
import feign.Logger;
/**
* The simulated device factory to create either {@link DMFSimulatedDevice} or
* {@link DDISimulatedDevice#}.
*
* @author Michael Hirsch
*
*/
@Service
public class SimulatedDeviceFactory {
private static final ScheduledExecutorService pollThreadPool = Executors.newScheduledThreadPool(4);
@Autowired
private DeviceSimulatorUpdater deviceUpdater;
/**
* Creating a simulated devices.
*
* @param id
* the ID of the simulated device
* @param tenant
* the tenant of the simulated device
* @param protocol
* the protocol of the device
* @return the created simulated device
*/
public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant, final Protocol protocol) {
return createSimulatedDevice(id, tenant, protocol, 30, null, null);
}
/**
* Creating a simulated device.
*
* @param id
* the ID of the simulated device
* @param tenant
* the tenant of the simulated device
* @param protocol
* the protocol which should be used be the simulated device
* @param pollDelaySec
* the poll delay time in seconds which should be used for
* {@link DDISimulatedDevice}s
* @param baseEndpoint
* the http base endpoint which should be used for
* {@link DDISimulatedDevice}s
* @param gatewayToken
* the gatewayToken to be used to authenticate
* {@link DDISimulatedDevice}s at the endpoint
* @return the created simulated device
*/
public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant, final Protocol protocol,
final int pollDelaySec, final URL baseEndpoint, final String gatewayToken) {
switch (protocol) {
case DMF_AMQP:
return new DMFSimulatedDevice(id, tenant);
case DDI_HTTP:
final ControllerResource controllerResource = Feign.builder().logger(new Logger.ErrorLogger())
.requestInterceptor(new GatewayTokenInterceptor(gatewayToken)).logLevel(Logger.Level.BASIC)
.target(ControllerResource.class, baseEndpoint.toString());
return new DDISimulatedDevice(id, tenant, pollDelaySec, controllerResource, pollThreadPool, deviceUpdater);
default:
throw new IllegalArgumentException("Protocol " + protocol + " unknown");
}
}
}

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.simulator;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -26,6 +27,12 @@ public class SimulationController {
@Autowired
private SpSenderService spSenderService;
@Autowired
private DeviceSimulatorRepository repository;
@Autowired
private SimulatedDeviceFactory deviceFactory;
/**
* The start resource to start a device creation.
*
@@ -43,7 +50,9 @@ public class SimulationController {
@RequestParam(value = "tenant", defaultValue = "DEFAULT") final String tenant) {
for (int i = 0; i < amount; i++) {
spSenderService.createOrUpdateThing(tenant, name + i);
final String deviceId = name + i;
repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, Protocol.DMF_AMQP));
spSenderService.createOrUpdateThing(tenant, deviceId);
}
return "Updated " + amount + " DMF connected targets!";

View File

@@ -132,6 +132,9 @@ public class AmqpConfiguration {
final SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory();
containerFactory.setDefaultRequeueRejected(false);
containerFactory.setConnectionFactory(connectionFactory);
containerFactory.setConcurrentConsumers(20);
containerFactory.setMaxConcurrentConsumers(20);
containerFactory.setPrefetchCount(20);
return containerFactory;
}

View File

@@ -15,6 +15,9 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.ActionStatus;
import org.eclipse.hawkbit.dmf.json.model.DownloadAndUpdateRequest;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
import org.eclipse.hawkbit.simulator.DeviceSimulatorUpdater;
import org.eclipse.hawkbit.simulator.DeviceSimulatorUpdater.UpdaterCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
@@ -40,6 +43,8 @@ public class SpReceiverService extends ReceiverService {
private final SpSenderService spSenderService;
private final DeviceSimulatorUpdater deviceUpdater;
/**
* Constructor.
*
@@ -51,12 +56,15 @@ public class SpReceiverService extends ReceiverService {
* the lwm2mSenderService
* @param spSenderService
* the spSenderService
* @param deviceUpdater
* the updater service to simulate update process
*/
@Autowired
public SpReceiverService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties,
final SpSenderService spSenderService) {
final SpSenderService spSenderService, final DeviceSimulatorUpdater deviceUpdater) {
super(rabbitTemplate, amqpProperties);
this.spSenderService = spSenderService;
this.deviceUpdater = deviceUpdater;
}
@@ -139,16 +147,23 @@ public class SpReceiverService extends ReceiverService {
spSenderService.sendActionStatusMessage(tenant, ActionStatus.RUNNING,
"device Simulator retrieved update request. proceeding with simulation.", actionId);
final SimulatedUpdate update = new SimulatedUpdate(tenant, thingId, actionId);
try {
Thread.sleep(1_000);
} catch (final InterruptedException e) {
LOGGER.error("Sleep interrupted", e);
}
spSenderService.finishUpdateProcess(update, "Simulation complete!");
deviceUpdater.startUpdate(tenant, thingId, actionId, downloadAndUpdateRequest.getSoftwareModules().get(0)
.getModuleVersion(), new UpdaterCallback() {
@Override
public void updateFinished(final AbstractSimulatedDevice device, final Long actionId) {
switch (device.getResponseStatus()) {
case SUCCESSFUL:
spSenderService.finishUpdateProcess(new SimulatedUpdate(device.getTenant(), device.getId(),
actionId), "Simulation complete!");
break;
case ERROR:
spSenderService.finishUpdateProcessWithError(new SimulatedUpdate(device.getTenant(),
device.getId(), actionId), "Simulation complete with error!");
break;
default:
break;
}
}
});
}
}

View File

@@ -0,0 +1,40 @@
/**
* 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.simulator.event;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
/**
* Event description which indicates the initialization of an update.
*
* @author Michael Hirsch
*
*/
public class InitUpdate {
private final AbstractSimulatedDevice device;
/**
* Creates new progress update event.
*
* @param device
* the device which progress has been updated
*/
public InitUpdate(final AbstractSimulatedDevice device) {
this.device = device;
}
/**
* @return the device of the event
*/
public AbstractSimulatedDevice getDevice() {
return device;
}
}

View File

@@ -0,0 +1,42 @@
/**
* 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.simulator.event;
import java.util.List;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
/**
* Event description which indicates an poll time update.
*
* @author Michael Hirsch
*
*/
public class NextPollCounterUpdate {
private final List<AbstractSimulatedDevice> devices;
/**
* Creates poll timer update event.
*
* @param devices
* the devices which progress has been updated
*/
public NextPollCounterUpdate(final List<AbstractSimulatedDevice> devices) {
this.devices = devices;
}
/**
* @return the devices of the event
*/
public List<AbstractSimulatedDevice> getDevices() {
return devices;
}
}

View File

@@ -0,0 +1,41 @@
/**
* 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.simulator.event;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
/**
* Event definition object which is published if the simulated device updated
* its update progress.
*
* @author Michael Hirsch
*
*/
public class ProgressUpdate {
private final AbstractSimulatedDevice device;
/**
* Creates new progress update event.
*
* @param device
* the device which progress has been updated
*/
public ProgressUpdate(final AbstractSimulatedDevice device) {
this.device = device;
}
/**
* @return the device of the event
*/
public AbstractSimulatedDevice getDevice() {
return device;
}
}

View File

@@ -0,0 +1,88 @@
/**
* 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.simulator.http;
import org.eclipse.hawkbit.simulator.DDISimulatedDevice;
import feign.Body;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
/**
* A feign based controller resource interface declaration for
* {@link DDISimulatedDevice}s using over HTTP.
*
* @author Michael Hirsch
*
*/
public interface ControllerResource {
/**
* The base poll URL for the devices to retrieve if there is an update
* available.
*
* @param tenant
* the tenant of the device
* @param controllerId
* the ID of the device
* @return the plain json response of the http request
*/
@RequestLine("GET /{tenant}/controller/v1/{controllerId}")
@Headers({ "Content-Type: application/json" })
String get(@Param("tenant") final String tenant, @Param("controllerId") final String controllerId);
/**
* Retrieving the deployment job response from the hawkbit update server.
*
* @param tenant
* the tenant for the simulated device
* @param controllerId
* the ID of the device
* @param actionId
* the ID of the action to retrieve
* @return the json response of the http request
*/
@RequestLine("GET /{tenant}/controller/v1/{controllerId}/deploymentBase/{actionId}")
@Headers({ "Content-Type: application/json" })
String getDeployment(@Param("tenant") final String tenant, @Param("controllerId") final String controllerId,
@Param("actionId") final long actionId);
/**
* Post a success update feedback to the hawkbit update server
*
* @param tenant
* the tenant of the device
* @param controllerId
* the ID of the device
* @param actionId
* the ID of the action to post feedback back
*/
@RequestLine("POST /{tenant}/controller/v1/{controllerId}/deploymentBase/{actionId}/feedback")
@Headers("Content-Type: application/json")
@Body("%7B\"id\":{actionId},\"time\":\"20140511T121314\",\"status\":%7B\"execution\":\"closed\",\"result\":%7B\"finished\":\"success\",\"progress\":%7B%7D%7D%7D%7D")
void postSuccessFeedback(@Param("tenant") final String tenant, @Param("controllerId") final String controllerId,
@Param("actionId") final long actionId);
/**
* Post a failure update feedback to the hawkbit update server
*
* @param tenant
* the tenant of the device
* @param controllerId
* the ID of the device
* @param actionId
* the ID of the action to post feedback back
*/
@RequestLine("POST /{tenant}/controller/v1/{controllerId}/deploymentBase/{actionId}/feedback")
@Headers("Content-Type: application/json")
@Body("%7B\"id\":{actionId},\"time\":\"20140511T121314\",\"status\":%7B\"execution\":\"closed\",\"result\":%7B\"finished\":\"failure\",\"progress\":%7B%7D%7D%7D%7D")
void postErrorFeedback(@Param("tenant") final String tenant, @Param("controllerId") final String controllerId,
@Param("actionId") final long actionId);
}

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.simulator.http;
import feign.RequestInterceptor;
import feign.RequestTemplate;
/**
* A feign interceptor to apply the gateway-token header to each http-request.
*
* @author Michael Hirsch
*
*/
public class GatewayTokenInterceptor implements RequestInterceptor {
private final String gatewayToken;
/**
* @param gatewayToken
* the gatwway token to be used in the http-header
*/
public GatewayTokenInterceptor(final String gatewayToken) {
this.gatewayToken = gatewayToken;
}
@Override
public void apply(final RequestTemplate template) {
template.header("Authorization", "GatewayToken " + gatewayToken);
}
}

View File

@@ -0,0 +1,233 @@
/**
* 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.simulator.ui;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.data.validator.NullValidator;
import com.vaadin.data.validator.RangeValidator;
import com.vaadin.data.validator.RegexpValidator;
import com.vaadin.server.FontAwesome;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.OptionGroup;
import com.vaadin.ui.TextField;
import com.vaadin.ui.Window;
/**
* Popup dialog window for setting the values of generating the simulated
* devices, e.g. the amount.
*
* @author Michael Hirsch
*
*/
public class GenerateDialog extends Window {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = LoggerFactory.getLogger(GenerateDialog.class);
private final FormLayout formLayout = new FormLayout();
/**
* Creates a new pop window for setting the configuration of simulating
* devices.
*
* @param callback
* the callback which is called when the dialog has been
* successfully confirmed.
*/
public GenerateDialog(final GenerateDialogCallback callback) {
formLayout.setSpacing(true);
formLayout.setMargin(true);
final TextField tf1 = new TextField("name prefix", "dmfSimulated");
tf1.setIcon(FontAwesome.INFO);
tf1.setRequired(true);
tf1.addValidator(new NullValidator("Must be given", false));
final TextField tf2 = new TextField("amount", new ObjectProperty<Integer>(10));
tf2.setIcon(FontAwesome.GEAR);
tf2.setRequired(true);
tf2.addValidator(new RangeValidator<Integer>("Must be between 1 and 30000", Integer.class, 1, 30000));
final TextField tf3 = new TextField("tenant", "default");
tf3.setIcon(FontAwesome.USER);
tf3.setRequired(true);
tf3.addValidator(new NullValidator("Must be given", false));
final TextField tf4 = new TextField("poll delay (sec)", new ObjectProperty<Integer>(10));
tf4.setIcon(FontAwesome.CLOCK_O);
tf4.setRequired(true);
tf4.setVisible(false);
tf4.addValidator(new RangeValidator<Integer>("Must be between 1 and 60", Integer.class, 1, 60));
final TextField tf5 = new TextField("base poll URL endpoint", "http://localhost:8080");
tf5.setColumns(50);
tf5.setIcon(FontAwesome.FLAG_O);
tf5.setRequired(true);
tf5.setVisible(false);
tf5.addValidator(new RegexpValidator(
"^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]", "is not an URL"));
final TextField tf6 = new TextField("gateway token", "");
tf6.setColumns(50);
tf6.setIcon(FontAwesome.FLAG_O);
tf6.setRequired(true);
tf6.setVisible(false);
final OptionGroup protocolGroup = new OptionGroup("Simulated Device Protocol");
protocolGroup.addItem(Protocol.DMF_AMQP);
protocolGroup.addItem(Protocol.DDI_HTTP);
protocolGroup.setItemCaption(Protocol.DMF_AMQP, "Device Management Federation API (AMQP push)");
protocolGroup.setItemCaption(Protocol.DDI_HTTP, "Direct Device Interface (HTTP poll)");
protocolGroup.setNullSelectionAllowed(false);
protocolGroup.select(Protocol.DMF_AMQP);
protocolGroup.addValueChangeListener(new ValueChangeListener() {
private static final long serialVersionUID = 1L;
@Override
public void valueChange(final ValueChangeEvent event) {
if (event.getProperty().getValue().equals(Protocol.DDI_HTTP)) {
tf4.setVisible(true);
tf5.setVisible(true);
tf6.setVisible(true);
} else {
tf4.setVisible(false);
tf5.setVisible(false);
tf6.setVisible(false);
}
}
});
final Button buttonOk = new Button("generate");
buttonOk.setImmediate(true);
buttonOk.setIcon(FontAwesome.GEARS);
buttonOk.addClickListener(new ClickListener() {
private static final long serialVersionUID = 1L;
@Override
public void buttonClick(final ClickEvent event) {
try {
callback.okButton(tf1.getValue(), tf3.getValue(), Integer.valueOf(tf2.getValue().replace(".", "")),
Integer.valueOf(tf4.getValue().replace(".", "")), new URL(tf5.getValue()), tf6.getValue(),
(Protocol) protocolGroup.getValue());
} catch (final NumberFormatException e) {
LOGGER.info(e.getMessage(), e);
} catch (final MalformedURLException e) {
LOGGER.info(e.getMessage(), e);
}
GenerateDialog.this.close();
}
});
tf1.addValueChangeListener(event -> checkValid(tf1, tf2, tf3, tf4, buttonOk));
tf2.addValueChangeListener(event -> checkValid(tf1, tf2, tf3, tf4, buttonOk));
tf3.addValueChangeListener(event -> checkValid(tf1, tf2, tf3, tf4, buttonOk));
formLayout.addComponent(tf1);
formLayout.addComponent(tf2);
formLayout.addComponent(tf3);
formLayout.addComponent(protocolGroup);
formLayout.addComponent(tf4);
formLayout.addComponent(tf5);
formLayout.addComponent(tf6);
formLayout.addComponent(buttonOk);
setCaption("Simulate Devices");
setContent(formLayout);
setResizable(false);
center();
}
private void checkValid(final TextField tf1, final TextField tf2, final TextField tf3, final TextField tf4,
final Button buttonOk) {
if (tf1.isValid() && tf2.isValid() && tf3.isValid() && tf4.isValid()) {
buttonOk.setEnabled(true);
} else {
buttonOk.setEnabled(false);
}
}
@Override
public int hashCode() {// NOSONAR - as this is generated
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((formLayout == null) ? 0 : formLayout.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {// NOSONAR - as this is generated
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final GenerateDialog other = (GenerateDialog) obj;
if (formLayout == null) {
if (other.formLayout != null) {
return false;
}
} else if (!formLayout.equals(other.formLayout)) {
return false;
}
return true;
}
/**
* Callback interface to retrieve the result from the dialog window.
*
* @author Michael Hirsch
*
*/
@FunctionalInterface
interface GenerateDialogCallback {
/**
* Callback method which is called when dialog closes with the OK
* button.
*
* @param namePrefix
* the parameter for name prefix for the simulated devices
* @param tenant
* the tenant for the simulated devices
* @param amount
* the number of simulated devices to be created
* @param pollDelay
* the delay poll time in seconds for DDI devices
* @param basePollURL
* the base http URL endpoint for DDI devices
* @param gatewayToken
* the gateway token header for authentication for DDI
* devices
* @param protocol
* the protocol to be used for the simulated devices to be
* generated
*/
void okButton(final String namePrefix, final String tenant, final int amount, final int pollDelay,
final URL basePollURL, final String gatewayToken, final Protocol protocol);
}
}

View File

@@ -0,0 +1,62 @@
/**
* 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.simulator.ui;
import org.springframework.beans.factory.annotation.Autowired;
import com.vaadin.annotations.Push;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.navigator.Navigator;
import com.vaadin.server.VaadinRequest;
import com.vaadin.shared.communication.PushMode;
import com.vaadin.shared.ui.ui.Transport;
import com.vaadin.spring.annotation.SpringUI;
import com.vaadin.spring.navigator.SpringViewProvider;
import com.vaadin.ui.Panel;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
/**
* The vaadin simulator UI which allows to generate simulated devices and show
* their current status and update progress.
*
* @author Michael Hirsch
*
*/
@SpringUI(path = "")
@Title("hawkBit Device Simulator")
@Theme(value = "simulator")
@Push(value = PushMode.AUTOMATIC, transport = Transport.WEBSOCKET)
public class SimulatorUI extends UI {
private static final long serialVersionUID = 1L;
private final VerticalLayout rootLayout = new VerticalLayout();
@Autowired
private SpringViewProvider viewProvider;
@Override
protected void init(final VaadinRequest request) {
rootLayout.setSizeFull();
final Panel viewContainer = new Panel();
viewContainer.setSizeFull();
rootLayout.addComponent(viewContainer);
rootLayout.setExpandRatio(viewContainer, 1.0F);
final Navigator navigator = new Navigator(this, viewContainer);
navigator.addProvider(viewProvider);
setContent(rootLayout);
}
}

View File

@@ -0,0 +1,341 @@
/**
* 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.simulator.ui;
import java.net.URL;
import java.util.List;
import java.util.Locale;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.ResponseStatus;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Status;
import org.eclipse.hawkbit.simulator.DeviceSimulatorRepository;
import org.eclipse.hawkbit.simulator.SimulatedDeviceFactory;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.eclipse.hawkbit.simulator.event.InitUpdate;
import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate;
import org.eclipse.hawkbit.simulator.event.ProgressUpdate;
import org.eclipse.hawkbit.simulator.ui.GenerateDialog.GenerateDialogCallback;
import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.BeanContainer;
import com.vaadin.data.util.BeanItem;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.server.FontAwesome;
import com.vaadin.spring.annotation.SpringView;
import com.vaadin.ui.Button;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.CellReference;
import com.vaadin.ui.Grid.CellStyleGenerator;
import com.vaadin.ui.Grid.SelectionMode;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.renderers.HtmlRenderer;
import com.vaadin.ui.renderers.ProgressBarRenderer;
/**
* Vaadin view which allows to generate devices through the DMF API and show the
* current simulated devices in a grid with their current status and update
* progress.
*
* @author Michael Hirsch
*
*/
@SpringView(name = "")
public class SimulatorView extends VerticalLayout implements View {
private static final long serialVersionUID = 1L;
@Autowired
private transient SpSenderService spSenderService;
@Autowired
private transient DeviceSimulatorRepository repository;
@Autowired
private transient SimulatedDeviceFactory deviceFactory;
@Autowired
private transient EventBus eventbus;
private final Label caption = new Label("DMF/DDI Simulated Devices");
private final HorizontalLayout toolbar = new HorizontalLayout();
private final Grid grid = new Grid();
private final ComboBox responseComboBox = new ComboBox("", Lists.newArrayList(ResponseStatus.SUCCESSFUL,
ResponseStatus.ERROR));
private BeanContainer<String, AbstractSimulatedDevice> beanContainer;
@Override
public void enter(final ViewChangeEvent event) {
eventbus.register(this);
setSizeFull();
// caption
caption.addStyleName("h2");
// toolbar
createToolbar();
beanContainer = new BeanContainer<>(AbstractSimulatedDevice.class);
beanContainer.setBeanIdProperty("id");
grid.setSizeFull();
grid.setCellStyleGenerator(new CellStyleGenerator() {
@Override
public String getStyle(final CellReference cellReference) {
return cellReference.getPropertyId().equals("status") ? "centeralign" : null;
}
});
grid.setSelectionMode(SelectionMode.NONE);
grid.setContainerDataSource(beanContainer);
grid.appendHeaderRow().getCell("responseStatus").setComponent(responseComboBox);
grid.setColumnOrder("id", "status", "swversion", "progress", "tenant", "protocol", "responseStatus",
"nextPollCounterSec");
// header widths
grid.getColumn("status").setMaximumWidth(80);
grid.getColumn("protocol").setMaximumWidth(180);
grid.getColumn("responseStatus").setMaximumWidth(240);
grid.getColumn("nextPollCounterSec").setMaximumWidth(210);
grid.getColumn("nextPollCounterSec").setHeaderCaption("Next Poll in (sec)");
grid.getColumn("swversion").setHeaderCaption("SW Version");
grid.getColumn("responseStatus").setHeaderCaption("Response Update Status");
grid.getColumn("progress").setRenderer(new ProgressBarRenderer());
grid.getColumn("protocol").setConverter(new Converter<String, Protocol>() {
@Override
public Protocol convertToModel(final String value, final Class<? extends Protocol> targetType,
final Locale locale) {
return null;
}
@Override
public String convertToPresentation(final Protocol value, final Class<? extends String> targetType,
final Locale locale) {
switch (value) {
case DDI_HTTP:
return "DDI API (http)";
case DMF_AMQP:
return "DMF API (amqp)";
default:
return "unknown";
}
}
@Override
public Class<Protocol> getModelType() {
return Protocol.class;
}
@Override
public Class<String> getPresentationType() {
return String.class;
}
});
grid.getColumn("status").setRenderer(new HtmlRenderer(), new Converter<String, Status>() {
private static final long serialVersionUID = 1L;
@Override
public Status convertToModel(final String value, final Class<? extends Status> targetType,
final Locale locale) {
return null;
}
@Override
public String convertToPresentation(final Status value, final Class<? extends String> targetType,
final Locale locale) {
String style = null;
switch (value) {
case UNKNWON:
style = "<span class=\"v-icon grayicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"gray\";\">&#x"
+ Integer.toHexString(FontAwesome.QUESTION_CIRCLE.getCodepoint()) + ";</span>";
break;
case PEDNING:
style = "<span class=\"v-icon yellowicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"yellow\";\">&#x" + Integer.toHexString(FontAwesome.REFRESH.getCodepoint())
+ ";</span>";
break;
case FINISH:
style = "<span class=\"v-icon greenicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"green\";\">&#x"
+ Integer.toHexString(FontAwesome.CHECK_CIRCLE.getCodepoint()) + ";</span>";
break;
case ERROR:
style = "<span class=\"v-icon redicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"red\";\">&#x"
+ Integer.toHexString(FontAwesome.EXCLAMATION_CIRCLE.getCodepoint()) + ";</span>";
break;
default:
throw new IllegalStateException("unknown value");
}
return style;
}
@Override
public Class<Status> getModelType() {
return Status.class;
}
@Override
public Class<String> getPresentationType() {
return String.class;
}
});
grid.removeColumn("tenant");
// grid combobox
responseComboBox.setItemIcon(ResponseStatus.SUCCESSFUL, FontAwesome.CHECK_CIRCLE);
responseComboBox.setItemIcon(ResponseStatus.ERROR, FontAwesome.EXCLAMATION_CIRCLE);
responseComboBox.setNullSelectionAllowed(false);
responseComboBox.setValue(ResponseStatus.SUCCESSFUL);
responseComboBox.addValueChangeListener(new ValueChangeListener() {
@Override
public void valueChange(final ValueChangeEvent event) {
beanContainer.getItemIds().forEach(
itemId -> beanContainer.getItem(itemId).getItemProperty("responseStatus")
.setValue(event.getProperty().getValue()));
}
});
// add all components
addComponent(caption);
addComponent(toolbar);
addComponent(grid);
setExpandRatio(grid, 1.0F);
// load beans
repository.getAll().forEach(device -> beanContainer.addBean(device));
}
@Override
public void detach() {
super.detach();
eventbus.unregister(this);
}
@Subscribe
public void pollCounterUpdate(final NextPollCounterUpdate update) {
final List<AbstractSimulatedDevice> devices = update.getDevices();
this.getUI().access(new Runnable() {
@Override
public void run() {
devices.forEach(device -> {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
if (item != null) {
item.getItemProperty("nextPollCounterSec").setValue(device.getNextPollCounterSec());
}
});
}
});
}
/**
* Method to retrieve {@link InitUpdate} events from the event bus.
*
* @param update
* the update event posted on the event bus
*/
@Subscribe
public void initUpdate(final InitUpdate update) {
final AbstractSimulatedDevice device = update.getDevice();
this.getUI().access(new Runnable() {
@Override
public void run() {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
if (item != null) {
item.getItemProperty("progress").setValue(device.getProgress());
item.getItemProperty("status").setValue(Status.PEDNING);
item.getItemProperty("swversion").setValue(device.getSwversion());
}
}
});
}
/**
* Method to retrieve {@link ProgressUpdate} events from the event bus.
*
* @param update
* the update event posted on the event bus
*/
@Subscribe
public void progessUpdate(final ProgressUpdate update) {
final AbstractSimulatedDevice device = update.getDevice();
this.getUI().access(new Runnable() {
@Override
public void run() {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
if (item != null) {
item.getItemProperty("progress").setValue(device.getProgress());
if (device.getProgress() >= 1) {
switch (device.getResponseStatus()) {
case SUCCESSFUL:
item.getItemProperty("status").setValue(Status.FINISH);
break;
case ERROR:
item.getItemProperty("status").setValue(Status.ERROR);
break;
default:
item.getItemProperty("status").setValue(Status.UNKNWON);
}
} else {
item.getItemProperty("status").setValue(Status.PEDNING);
}
}
}
});
}
private void createToolbar() {
final Button createDevicesButton = new Button("generate...");
createDevicesButton.setIcon(FontAwesome.GEARS);
createDevicesButton.addClickListener(event -> openGenerateDialog());
final Button clearDevicesButton = new Button("clear");
clearDevicesButton.setIcon(FontAwesome.ERASER);
clearDevicesButton.addClickListener(event -> clearSimulatedDevices());
toolbar.addComponent(createDevicesButton);
toolbar.addComponent(clearDevicesButton);
toolbar.setSpacing(true);
}
private void clearSimulatedDevices() {
repository.clear();
beanContainer.removeAllItems();
}
private void openGenerateDialog() {
UI.getCurrent().addWindow(new GenerateDialog(new GenerateDialogCallback() {
@Override
public void okButton(final String namePrefix, final String tenant, final int amount, final int pollDelay,
final URL basePollUrl, final String gatewayToken, final Protocol protocol) {
for (int index = 0; index < amount; index++) {
final String deviceId = namePrefix + index;
beanContainer.addBean(repository.add(deviceFactory.createSimulatedDevice(deviceId,
tenant.toLowerCase(), protocol, pollDelay, basePollUrl, gatewayToken)));
spSenderService.createOrUpdateThing(tenant, deviceId);
}
}
}));
}
}

View File

@@ -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
*/
// Import valo after setting the parameters
@import "../valo/valo";
.simulator{
@include valo;
.yellowicon {
color: orange;
}
.greenicon {
color: green;
}
.grayicon {
color: gray;
}
.redicon {
color: red;
}
.v-grid-cell.centeralign {
text-align: center;
}
}

View File

@@ -25,7 +25,7 @@ spring.rabbitmq.virtualHost=/
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.dynamic=true
spring.rabbitmq.listener.prefetch=100
# SECURITY (SecurityProperties)
security.user.name=${BASIC_USERNAME:admin}
@@ -44,6 +44,6 @@ security.headers.frame=false
security.headers.content-type=false
security.headers.hsts=all
security.sessions=stateless
security.ignored=
security.ignored=/VAADIN/**
server.port=8083

View File

@@ -17,10 +17,6 @@ package org.eclipse.hawkbit.repository;
*/
public enum ActionStatusFields implements FieldNameProvider {
/**
* The type field.
*/
TYPE("type"),
/**
* The id field.
*/

View File

@@ -209,7 +209,7 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware {
/*
* (non-Javadoc)
*
*
* @see org.springframework.context.EnvironmentAware#setEnvironment(org.
* springframework.core.env. Environment)
*/

View File

@@ -0,0 +1,89 @@
/**
* 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.rsql;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import org.eclipse.hawkbit.AbstractIntegrationTest;
import org.eclipse.hawkbit.repository.ActionFields;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Target;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.domain.Specification;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - RSQL filtering")
@Stories("RSQL filter actions")
public class RSQLActionFieldsTest extends AbstractIntegrationTest {
private Target target;
private Action action;
@Before
public void setupBeforeTest() {
target = new Target("targetId123");
target.setDescription("targetId123");
targetManagement.createTarget(target);
action = new Action();
action.setActionType(ActionType.SOFT);
target.getActions().add(action);
action.setTarget(target);
actionRepository.save(action);
for (int i = 0; i < 10; i++) {
final Action newAction = new Action();
newAction.setActionType(ActionType.SOFT);
newAction.setActive(i % 2 == 0);
newAction.setTarget(target);
actionRepository.save(newAction);
target.getActions().add(newAction);
}
}
@Test
@Description("Test filter action by id")
public void testFilterByParameterId() {
assertRSQLQuery(ActionFields.ID.name() + "==" + action.getId(), 1);
assertRSQLQuery(ActionFields.ID.name() + "==noExist*", 0);
assertRSQLQuery(ActionFields.ID.name() + "=in=(" + action.getId() + ",1000000)", 1);
assertRSQLQuery(ActionFields.ID.name() + "=out=(" + action.getId() + ",1000000)", 10);
}
@Test
@Description("Test action by status")
public void testFilterByParameterStatus() {
assertRSQLQuery(ActionFields.STATUS.name() + "==pending", 5);
assertRSQLQuery(ActionFields.STATUS.name() + "=in=(pending)", 5);
assertRSQLQuery(ActionFields.STATUS.name() + "=out=(pending)", 6);
try {
assertRSQLQuery(ActionFields.STATUS.name() + "==true", 5);
fail();
} catch (final RSQLParameterUnsupportedFieldException e) {
}
}
private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) {
final Specification<Action> parse = RSQLUtility.parse(rsqlParam, ActionFields.class);
final Slice<Action> findEnitity = deploymentManagement.findActionsByTarget(parse, target,
new PageRequest(0, 100));
final long countAllEntities = deploymentManagement.countActionsByTarget(parse, target);
assertThat(findEnitity).isNotNull();
assertThat(countAllEntities).isEqualTo(expectedEntities);
}
}

View File

@@ -0,0 +1,140 @@
/**
* 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.rsql;
import static org.fest.assertions.api.Assertions.assertThat;
import java.util.Arrays;
import org.eclipse.hawkbit.AbstractIntegrationTest;
import org.eclipse.hawkbit.TestDataUtil;
import org.eclipse.hawkbit.repository.DistributionSetFields;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - RSQL filtering")
@Stories("RSQL filter distribution set")
public class RSQLDistributionSetFieldTest extends AbstractIntegrationTest {
@Before
public void seuptBeforeTest() {
final DistributionSet ds = TestDataUtil.generateDistributionSet("DS", softwareManagement,
distributionSetManagement);
ds.setDescription("DS");
ds.getMetadata().add(new DistributionSetMetadata("metaKey", ds, "metaValue"));
distributionSetManagement.updateDistributionSet(ds);
final DistributionSet ds2 = TestDataUtil
.generateDistributionSets("NewDS", 3, softwareManagement, distributionSetManagement).get(0);
ds2.setDescription("DS2");
ds2.getMetadata().add(new DistributionSetMetadata("metaKey", ds2, "value"));
distributionSetManagement.updateDistributionSet(ds2);
final DistributionSetTag targetTag = tagManagement.createDistributionSetTag(new DistributionSetTag("Tag1"));
tagManagement.createDistributionSetTag(new DistributionSetTag("Tag2"));
tagManagement.createDistributionSetTag(new DistributionSetTag("Tag3"));
tagManagement.createDistributionSetTag(new DistributionSetTag("Tag4"));
distributionSetManagement.assignTag(Arrays.asList(ds.getId(), ds2.getId()), targetTag);
}
@Test
@Description("Test filter distribution set by id")
public void testFilterByParameterId() {
assertRSQLQuery(DistributionSetFields.ID.name() + "==*", 4);
}
@Test
@Description("Test filter distribution set by name")
public void testFilterByParameterName() {
assertRSQLQuery(DistributionSetFields.NAME.name() + "==DS", 1);
assertRSQLQuery(DistributionSetFields.NAME.name() + "==*DS", 4);
assertRSQLQuery(DistributionSetFields.NAME.name() + "==noExist*", 0);
assertRSQLQuery(DistributionSetFields.NAME.name() + "=in=(DS,notexist)", 1);
assertRSQLQuery(DistributionSetFields.NAME.name() + "=out=(DS,notexist)", 3);
}
@Test
@Description("Test filter distribution set by description")
public void testFilterByParameterDescription() {
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==DS", 1);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==DS*", 2);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==noExist*", 0);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "=in=(DS,notexist)", 1);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "=out=(DS,notexist)", 3);
}
@Test
@Description("Test filter distribution set by version")
public void testFilterByParameterVersion() {
assertRSQLQuery(DistributionSetFields.VERSION.name() + "==v1.0", 2);
assertRSQLQuery(DistributionSetFields.VERSION.name() + "!=v1.0", 2);
assertRSQLQuery(DistributionSetFields.VERSION.name() + "=in=(v1.0,v1.1)", 3);
assertRSQLQuery(DistributionSetFields.VERSION.name() + "=out=(v1.0,error)", 2);
}
@Test
@Description("Test filter distribution set by complete property")
public void testFilterByAttribute() {
assertRSQLQuery(DistributionSetFields.COMPLETE.name() + "==true", 4);
assertRSQLQuery(DistributionSetFields.COMPLETE.name() + "==noExist*", 0);
assertRSQLQuery(DistributionSetFields.COMPLETE.name() + "=in=(true)", 4);
assertRSQLQuery(DistributionSetFields.COMPLETE.name() + "=out=(true)", 0);
}
@Test
@Description("Test filter distribution set by tag")
public void testFilterByTag() {
assertRSQLQuery(DistributionSetFields.TAG.name() + "==Tag1", 2);
assertRSQLQuery(DistributionSetFields.TAG.name() + "==T*", 2);
assertRSQLQuery(DistributionSetFields.TAG.name() + "==noExist*", 0);
assertRSQLQuery(DistributionSetFields.TAG.name() + "=in=(Tag1,notexist)", 2);
assertRSQLQuery(DistributionSetFields.TAG.name() + "=out=(Tag1,notexist)", 0);
}
@Test
@Description("Test filter distribution set by type")
public void testFilterByType() {
assertRSQLQuery(DistributionSetFields.TYPE.name() + "==ecl_os_app_jvm", 4);
assertRSQLQuery(DistributionSetFields.TYPE.name() + "==noExist*", 0);
assertRSQLQuery(DistributionSetFields.TYPE.name() + "=in=(ecl_os_app_jvm,ecl)", 4);
assertRSQLQuery(DistributionSetFields.TYPE.name() + "=out=(ecl_os_app_jvm)", 0);
}
@Test
@Description("")
public void testFilterByMetadata() {
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey==metaValue", 1);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey==*v*", 2);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey==noExist*", 0);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey=out=(metaValue,notexist)", 1);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".notExist==metaValue", 0);
}
private void assertRSQLQuery(final String rsqlParam, final long excpectedEntity) {
final Page<DistributionSet> find = distributionSetManagement.findDistributionSetsAll(
RSQLUtility.parse(rsqlParam, DistributionSetFields.class), new PageRequest(0, 100), false);
final long countAll = find.getTotalElements();
assertThat(find).isNotNull();
assertThat(countAll).isEqualTo(excpectedEntity);
}
}

View File

@@ -0,0 +1,74 @@
/**
* 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.rsql;
import static org.fest.assertions.api.Assertions.assertThat;
import org.eclipse.hawkbit.AbstractIntegrationTest;
import org.eclipse.hawkbit.TestDataUtil;
import org.eclipse.hawkbit.repository.DistributionSetMetadataFields;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - RSQL filtering")
@Stories("RSQL filter distribution set metadata")
public class RSQLDistributionSetMetadataFieldsTest extends AbstractIntegrationTest {
private Long distributionSetId;
@Before
public void setupBeforeTest() {
final DistributionSet distributionSet = TestDataUtil.generateDistributionSet("DS", softwareManagement,
distributionSetManagement);
distributionSetId = distributionSet.getId();
for (int i = 0; i < 5; i++) {
final DistributionSetMetadata distributionSetMetadata = new DistributionSetMetadata("" + i, distributionSet,
"" + i);
distributionSet.getMetadata().add(distributionSetMetadata);
}
distributionSetManagement.updateDistributionSet(distributionSet);
}
@Test
@Description("Test filter distribution set metadata by key")
public void testFilterByParameterKey() {
assertRSQLQuery(DistributionSetMetadataFields.KEY.name() + "==1", 1);
assertRSQLQuery(DistributionSetMetadataFields.KEY.name() + "!=1", 4);
assertRSQLQuery(DistributionSetMetadataFields.KEY.name() + "=in=(1,2)", 2);
assertRSQLQuery(DistributionSetMetadataFields.KEY.name() + "=out=(1,2)", 3);
}
@Test
@Description("Test filter distribution set metadata by value")
public void testFilterByParameterValue() {
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "==1", 1);
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "!=1", 4);
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "=in=(1,2)", 2);
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "=out=(1,2)", 3);
}
private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) {
final Page<DistributionSetMetadata> findEnitity = distributionSetManagement
.findDistributionSetMetadataByDistributionSetId(distributionSetId,
RSQLUtility.parse(rsqlParam, DistributionSetMetadataFields.class), new PageRequest(0, 100));
final long countAllEntities = findEnitity.getTotalElements();
assertThat(findEnitity).isNotNull();
assertThat(countAllEntities).isEqualTo(expectedEntities);
}
}

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.repository.rsql;
import static org.fest.assertions.api.Assertions.assertThat;
import org.eclipse.hawkbit.AbstractIntegrationTest;
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - RSQL filtering")
@Stories("RSQL filter software module")
public class RSQLSoftwareModuleFieldTest extends AbstractIntegrationTest {
@Before
public void seuptBeforeTest() {
final SoftwareModule ah = softwareManagement
.createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", "agent-hub", ""));
softwareManagement.createSoftwareModule(new SoftwareModule(runtimeType, "oracle-jre", "1.7.2", "aa", ""));
softwareManagement.createSoftwareModule(new SoftwareModule(osType, "poky", "3.0.2", "aa", ""));
final SoftwareModule ah2 = softwareManagement
.createSoftwareModule(new SoftwareModule(appType, "agent-hub2", "1.0.1", "agent-hub2", ""));
final SoftwareModuleMetadata softwareModuleMetadata = new SoftwareModuleMetadata("metaKey", ah, "metaValue");
softwareManagement.createSoftwareModuleMetadata(softwareModuleMetadata);
ah.getMetadata().add(softwareModuleMetadata);
softwareManagement.updateSoftwareModule(ah);
final SoftwareModuleMetadata softwareModuleMetadata2 = new SoftwareModuleMetadata("metaKey", ah2, "value");
softwareManagement.createSoftwareModuleMetadata(softwareModuleMetadata2);
ah2.getMetadata().add(softwareModuleMetadata2);
softwareManagement.updateSoftwareModule(ah2);
}
@Test
@Description("Test filter software module by id")
public void testFilterByParameterId() {
assertRSQLQuery(SoftwareModuleFields.ID.name() + "==*", 4);
}
@Test
@Description("Test filter software module by name")
public void testFilterByParameterName() {
assertRSQLQuery(SoftwareModuleFields.NAME.name() + "==agent-hub", 1);
assertRSQLQuery(SoftwareModuleFields.NAME.name() + "==agent-hub*", 2);
assertRSQLQuery(SoftwareModuleFields.NAME.name() + "==noExist*", 0);
assertRSQLQuery(SoftwareModuleFields.NAME.name() + "=in=(agent-hub,notexist)", 1);
assertRSQLQuery(SoftwareModuleFields.NAME.name() + "=out=(agent-hub,notexist)", 3);
}
@Test
@Description("Test filter software module by description")
public void testFilterByParameterDescription() {
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "==agent-hub", 1);
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "==noExist*", 0);
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "=in=(agent-hub,notexist)", 1);
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "=out=(agent-hub,notexist)", 3);
}
@Test
@Description("Test filter software module by version")
public void testFilterByParameterVersion() {
assertRSQLQuery(SoftwareModuleFields.VERSION.name() + "==1.0.1", 2);
assertRSQLQuery(SoftwareModuleFields.VERSION.name() + "!=v1.0", 4);
assertRSQLQuery(SoftwareModuleFields.VERSION.name() + "=in=(1.0.1,1.0.2)", 2);
assertRSQLQuery(SoftwareModuleFields.VERSION.name() + "=out=(1.0.1)", 2);
}
@Test
@Description("Test filter software module by type")
public void testFilterByType() {
assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "==application", 2);
assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "==noExist*", 0);
assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "=in=(application)", 2);
assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "=out=(application)", 2);
}
@Test
@Description("")
public void testFilterByMetadata() {
assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".metaKey==metaValue", 1);
assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".metaKey==*v*", 2);
assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".metaKey==noExist*", 0);
assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1);
assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".metaKey=out=(metaValue,notexist)", 1);
assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".notExist==metaValue", 0);
}
private void assertRSQLQuery(final String rsqlParam, final long excpectedEntity) {
final Page<SoftwareModule> find = softwareManagement.findSoftwareModulesByPredicate(
RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class), new PageRequest(0, 100));
final long countAll = find.getTotalElements();
assertThat(find).isNotNull();
assertThat(countAll).isEqualTo(excpectedEntity);
}
}

View File

@@ -0,0 +1,76 @@
/**
* 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.rsql;
import static org.fest.assertions.api.Assertions.assertThat;
import org.eclipse.hawkbit.AbstractIntegrationTest;
import org.eclipse.hawkbit.TestDataUtil;
import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - RSQL filtering")
@Stories("RSQL filter software module metadata")
public class RSQLSoftwareModuleMetadataFieldsTest extends AbstractIntegrationTest {
private Long softwareModuleId;
@Before
public void setupBeforeTest() {
final SoftwareModule softwareModule = softwareManagement.createSoftwareModule(
new SoftwareModule(TestDataUtil.findOrCreateSoftwareModuleType(softwareManagement, "application"),
"application", "1.0.0", "Desc", "vendor Limited, California"));
softwareModuleId = softwareModule.getId();
for (int i = 0; i < 5; i++) {
final SoftwareModuleMetadata metadata = new SoftwareModuleMetadata("" + i, softwareModule, "" + i);
softwareModule.getMetadata().add(metadata);
softwareModuleMetadataRepository.save(metadata);
}
softwareManagement.updateSoftwareModule(softwareModule);
}
@Test
@Description("Test filter software module metadata by key")
public void testFilterByParameterKey() {
assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "==1", 1);
assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "!=1", 4);
assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "=in=(1,2)", 2);
assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "=out=(1,2)", 3);
}
@Test
@Description("Test fitler software module metadata status by value")
public void testFilterByParameterValue() {
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "==1", 1);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "!=1", 4);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=in=(1,2)", 2);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=out=(1,2)", 3);
}
private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) {
final Page<SoftwareModuleMetadata> findEnitity = softwareManagement
.findSoftwareModuleMetadataBySoftwareModuleId(softwareModuleId,
RSQLUtility.parse(rsqlParam, SoftwareModuleMetadataFields.class), new PageRequest(0, 100));
final long countAllEntities = findEnitity.getTotalElements();
assertThat(findEnitity).isNotNull();
assertThat(countAllEntities).isEqualTo(expectedEntities);
}
}

View File

@@ -0,0 +1,68 @@
/**
* 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.rsql;
import static org.fest.assertions.api.Assertions.assertThat;
import org.eclipse.hawkbit.AbstractIntegrationTest;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.junit.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - RSQL filtering")
@Stories("RSQL filter software module test type")
public class RSQLSoftwareModuleTypeFieldsTest extends AbstractIntegrationTest {
@Test
@Description("Test filter software module test type by id")
public void testFilterByParameterId() {
assertRSQLQuery(SoftwareModuleTypeFields.ID.name() + "==*", 3);
}
@Test
@Description("Test filter software module test type by name")
public void testFilterByParameterName() {
assertRSQLQuery(SoftwareModuleTypeFields.NAME.name() + "==ECL*", 3);
}
@Test
@Description("Test filter software module test type by description")
public void testFilterByParameterDescription() {
assertRSQLQuery(SoftwareModuleTypeFields.DESCRIPTION.name() + "==Updated*", 3);
assertRSQLQuery(SoftwareModuleTypeFields.DESCRIPTION.name() + "==noExist*", 0);
}
@Test
@Description("Test filter software module test type by key")
public void testFilterByParameterKey() {
assertRSQLQuery(SoftwareModuleTypeFields.KEY.name() + "==os", 1);
assertRSQLQuery(SoftwareModuleTypeFields.KEY.name() + "=in=(os)", 1);
assertRSQLQuery(SoftwareModuleTypeFields.KEY.name() + "=out=(os)", 2);
}
@Test
@Description("Test filter software module test type by max")
public void testFilterByMaxAssignment() {
assertRSQLQuery(SoftwareModuleTypeFields.MAX.name() + "==1", 3);
}
private void assertRSQLQuery(final String rsqlParam, final long excpectedEntity) {
final Page<SoftwareModuleType> find = softwareManagement.findSoftwareModuleTypesByPredicate(
RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class), new PageRequest(0, 100));
final long countAll = find.getTotalElements();
assertThat(find).isNotNull();
assertThat(countAll).isEqualTo(excpectedEntity);
}
}

View File

@@ -0,0 +1,119 @@
/**
* 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.rsql;
import static org.fest.assertions.api.Assertions.assertThat;
import org.eclipse.hawkbit.AbstractIntegrationTest;
import org.eclipse.hawkbit.repository.TagFields;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - RSQL filtering")
@Stories("RSQL filter target and distribution set tags")
public class RSQLTagFieldsTest extends AbstractIntegrationTest {
@Before
public void seuptBeforeTest() {
for (int i = 0; i < 5; i++) {
final TargetTag targetTag = new TargetTag("" + i, "" + i, i % 2 == 0 ? "red" : "blue");
tagManagement.createTargetTag(targetTag);
final DistributionSetTag distributionSetTag = new DistributionSetTag("" + i, "" + i,
i % 2 == 0 ? "red" : "blue");
tagManagement.createDistributionSetTag(distributionSetTag);
}
}
@Test
@Description("Test filter target tag by name")
public void testFilterTargetTagByParameterName() {
assertRSQLQueryTarget(TagFields.NAME.name() + "==1", 1);
assertRSQLQueryTarget(TagFields.NAME.name() + "==*", 5);
assertRSQLQueryTarget(TagFields.NAME.name() + "==noExist*", 0);
assertRSQLQueryTarget(TagFields.NAME.name() + "=in=(1,notexist)", 1);
assertRSQLQueryTarget(TagFields.NAME.name() + "=out=(1,notexist)", 4);
}
@Test
@Description("Test filter target tag by description")
public void testFilterTargetTagByParameterDescription() {
assertRSQLQueryTarget(TagFields.DESCRIPTION.name() + "==1", 1);
assertRSQLQueryTarget(TagFields.DESCRIPTION.name() + "==*", 5);
assertRSQLQueryTarget(TagFields.DESCRIPTION.name() + "==noExist*", 0);
assertRSQLQueryTarget(TagFields.DESCRIPTION.name() + "=in=(1,notexist)", 1);
assertRSQLQueryTarget(TagFields.DESCRIPTION.name() + "=out=(1,notexist)", 4);
}
@Test
@Description("Test filter target tag by colour")
public void testFilterTargetTagByParameterColour() {
assertRSQLQueryTarget(TagFields.COLOUR.name() + "==red", 3);
assertRSQLQueryTarget(TagFields.COLOUR.name() + "==r*", 3);
assertRSQLQueryTarget(TagFields.COLOUR.name() + "==noExist*", 0);
assertRSQLQueryTarget(TagFields.COLOUR.name() + "=in=(red,notexist)", 3);
assertRSQLQueryTarget(TagFields.COLOUR.name() + "=out=(red,notexist)", 2);
}
@Test
@Description("Test filter distribution set tag by name")
public void testFilterDistributionSetTagByParameterName() {
assertRSQLQueryDistributionSet(TagFields.NAME.name() + "==1", 1);
assertRSQLQueryDistributionSet(TagFields.NAME.name() + "==*", 5);
assertRSQLQueryDistributionSet(TagFields.NAME.name() + "==noExist*", 0);
assertRSQLQueryDistributionSet(TagFields.NAME.name() + "=in=(1,2)", 2);
assertRSQLQueryDistributionSet(TagFields.NAME.name() + "=out=(1,2)", 3);
}
@Test
@Description("Test filter distribution set by description")
public void testFilterDistributionSetTagByParameterDescription() {
assertRSQLQueryDistributionSet(TagFields.DESCRIPTION.name() + "==1", 1);
assertRSQLQueryDistributionSet(TagFields.DESCRIPTION.name() + "==*", 5);
assertRSQLQueryDistributionSet(TagFields.DESCRIPTION.name() + "==noExist*", 0);
assertRSQLQueryDistributionSet(TagFields.DESCRIPTION.name() + "=in=(1,2)", 2);
assertRSQLQueryDistributionSet(TagFields.DESCRIPTION.name() + "=out=(1,2)", 3);
}
@Test
@Description("Test filter distribution set by colour")
public void testFilterDistributionSetTagByParameterColour() {
assertRSQLQueryDistributionSet(TagFields.COLOUR.name() + "==red", 3);
assertRSQLQueryDistributionSet(TagFields.COLOUR.name() + "==r*", 3);
assertRSQLQueryDistributionSet(TagFields.COLOUR.name() + "==noExist*", 0);
assertRSQLQueryDistributionSet(TagFields.COLOUR.name() + "=in=(red,notexist)", 3);
assertRSQLQueryDistributionSet(TagFields.COLOUR.name() + "=out=(red,notexist)", 2);
}
private void assertRSQLQueryDistributionSet(final String rsqlParam, final long expectedEntities) {
final Page<DistributionSetTag> findEnitity = tagManagement
.findAllDistributionSetTags(RSQLUtility.parse(rsqlParam, TagFields.class), new PageRequest(0, 100));
final long countAllEntities = findEnitity.getTotalElements();
assertThat(findEnitity).isNotNull();
assertThat(countAllEntities).isEqualTo(expectedEntities);
}
private void assertRSQLQueryTarget(final String rsqlParam, final long expectedEntities) {
final Page<TargetTag> findEnitity = tagManagement
.findAllTargetTags(RSQLUtility.parse(rsqlParam, TagFields.class), new PageRequest(0, 100));
final long countAllEntities = findEnitity.getTotalElements();
assertThat(findEnitity).isNotNull();
assertThat(countAllEntities).isEqualTo(expectedEntities);
}
}

View File

@@ -0,0 +1,171 @@
/**
* 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.rsql;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import java.util.Arrays;
import org.eclipse.hawkbit.AbstractIntegrationTest;
import org.eclipse.hawkbit.TestDataUtil;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - RSQL filtering")
@Stories("RSQL filter target")
public class RSQLTargetFieldTest extends AbstractIntegrationTest {
@Before
public void seuptBeforeTest() {
final DistributionSet ds = TestDataUtil.generateDistributionSet("AssignedDs", softwareManagement,
distributionSetManagement);
final Target target = new Target("targetId123");
target.setDescription("targetId123");
final TargetInfo targetInfo = new TargetInfo(target);
targetInfo.getControllerAttributes().put("revision", "1.1");
target.setTargetInfo(targetInfo);
target.getTargetInfo().setUpdateStatus(TargetUpdateStatus.PENDING);
targetManagement.createTarget(target);
final Target target2 = new Target("targetId1234");
target2.setDescription("targetId1234");
final TargetInfo targetInfo2 = new TargetInfo(target2);
targetInfo2.getControllerAttributes().put("revision", "1.2");
target2.setTargetInfo(targetInfo2);
targetManagement.createTarget(target2);
targetManagement.createTarget(new Target("targetId1235"));
targetManagement.createTarget(new Target("targetId1236"));
final TargetTag targetTag = tagManagement.createTargetTag(new TargetTag("Tag1"));
tagManagement.createTargetTag(new TargetTag("Tag2"));
tagManagement.createTargetTag(new TargetTag("Tag3"));
tagManagement.createTargetTag(new TargetTag("Tag4"));
targetManagement.assignTag(Arrays.asList(target.getControllerId(), target2.getControllerId()), targetTag);
deploymentManagement.assignDistributionSet(ds.getId(), target.getControllerId());
}
@Test
@Description("Test filter target by (controller) id")
public void testFilterByParameterId() {
assertRSQLQuery(TargetFields.ID.name() + "==targetId123", 1);
assertRSQLQuery(TargetFields.ID.name() + "==target*", 4);
assertRSQLQuery(TargetFields.ID.name() + "==noExist*", 0);
assertRSQLQuery(TargetFields.ID.name() + "=in=(targetId123,notexist)", 1);
assertRSQLQuery(TargetFields.ID.name() + "=out=(targetId123,notexist)", 3);
}
@Test
@Description("Test filter target by name")
public void testFilterByParameterName() {
assertRSQLQuery(TargetFields.NAME.name() + "==targetId123", 1);
assertRSQLQuery(TargetFields.NAME.name() + "==target*", 4);
assertRSQLQuery(TargetFields.NAME.name() + "==noExist*", 0);
assertRSQLQuery(TargetFields.NAME.name() + "=in=(targetId123,notexist)", 1);
assertRSQLQuery(TargetFields.NAME.name() + "=out=(targetId123,notexist)", 3);
}
@Test
@Description("Test filter target by description")
public void testFilterByParameterDescription() {
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==targetId123", 1);
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==target*", 2);
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==noExist*", 0);
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "=in=(targetId123,notexist)", 1);
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "=out=(targetId123,notexist)", 1);
}
@Test
@Description("Test filter target by controller id")
public void testFilterByParameterControllerId() {
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "==targetId123", 1);
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "==target*", 4);
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "==noExist*", 0);
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "=in=(targetId123,notexist)", 1);
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "=out=(targetId123,notexist)", 3);
}
@Test
@Description("Test filter target by status")
public void testFilterByParameterUpdateStatus() {
assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "==pending", 1);
assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "!=pending", 3);
try {
assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "==noExist*", 0);
fail();
} catch (final RSQLParameterUnsupportedFieldException e) {
}
assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "=in=(pending,error)", 1);
assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "=out=(pending,error)", 3);
}
@Test
@Description("Test filter target by attribute")
public void testFilterByAttribute() {
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==1.1", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==1*", 2);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==noExist*", 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision=in=(1.1,notexist)", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision=out=(1.1)", 1);
}
@Test
@Description("Test filter target by assigned ds name")
public void testFilterByAssignedDsName() {
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name==AssignedDs", 1);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name==A*", 1);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name==noExist*", 0);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name=in=(AssignedDs,notexist)", 1);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name=out=(AssignedDs,notexist)", 0);
}
@Test
@Description("Test filter target by assigned ds version")
public void testFilterByAssignedDsVersion() {
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==v1.0", 1);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==*1*", 1);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==noExist*", 0);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version=in=(v1.0,notexist)", 1);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version=out=(v1.0,notexist)", 0);
}
@Test
@Description("Test filter target by tag")
public void testFilterByTag() {
assertRSQLQuery(TargetFields.TAG.name() + "==Tag1", 2);
assertRSQLQuery(TargetFields.TAG.name() + "==T*", 2);
assertRSQLQuery(TargetFields.TAG.name() + "==noExist*", 0);
assertRSQLQuery(TargetFields.TAG.name() + "=in=(Tag1,notexist)", 2);
assertRSQLQuery(TargetFields.TAG.name() + "=out=(Tag1,notexist)", 0);
}
private void assertRSQLQuery(final String rsqlParam, final long expcetedTargets) {
final Page<Target> findTargetPage = targetManagement
.findTargetsAll(RSQLUtility.parse(rsqlParam, TargetFields.class), new PageRequest(0, 100));
final long countTargetsAll = findTargetPage.getTotalElements();
assertThat(findTargetPage).isNotNull();
assertThat(countTargetsAll).isEqualTo(expcetedTargets);
}
}

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.resource;
package org.eclipse.hawkbit.repository.rsql;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
@@ -31,9 +31,6 @@ import org.eclipse.hawkbit.repository.FieldNameProvider;
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.rsql.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.rsql.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.rsql.RSQLUtility;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -43,7 +40,7 @@ import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@RunWith(MockitoJUnitRunner.class)
@Features("Component Tests - Management RESTful API")
@Features("Component Tests - RSQL filtering")
@Stories("RSQL search utility")
// TODO: fully document tests -> @Description for long text and reasonable
// method name as short text