Rename and split rest resources ddi, mgmt and system
Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.system.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
/**
|
||||
* Annotation to enable {@link ComponentScan} in the resource package to setup
|
||||
* all {@link Controller} annotated classes and setup the System API.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
public @interface EnableSystemApi {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* 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.system.rest.resource;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.report.model.SystemUsageReport;
|
||||
import org.eclipse.hawkbit.report.model.TenantUsage;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.system.json.model.systemmanagement.SystemCache;
|
||||
import org.eclipse.hawkbit.system.json.model.systemmanagement.SystemStatisticsRest;
|
||||
import org.eclipse.hawkbit.system.json.model.systemmanagement.SystemTenantServiceUsage;
|
||||
import org.eclipse.hawkbit.system.rest.api.SystemManagementRestApi;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* {@link SystemManagement} capabilities by REST.
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
public class SystemManagementResource implements SystemManagementRestApi {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SystemManagementResource.class);
|
||||
|
||||
@Autowired
|
||||
private SystemManagement systemManagement;
|
||||
|
||||
@Autowired
|
||||
private CacheManager cacheManager;
|
||||
|
||||
/**
|
||||
* Deletes the tenant data of a given tenant. USE WITH CARE!
|
||||
*
|
||||
* @param tenant
|
||||
* to delete
|
||||
* @return HttpStatus.OK
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteTenant(final String tenant) {
|
||||
systemManagement.deleteTenant(tenant);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects and returns system usage statistics. It provides a system wide
|
||||
* overview and tenant based stats.
|
||||
*
|
||||
* @return system usage statistics
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<SystemStatisticsRest> getSystemUsageStats() {
|
||||
final SystemUsageReport report = systemManagement.getSystemUsageStatistics();
|
||||
|
||||
final SystemStatisticsRest result = new SystemStatisticsRest().setOverallActions(report.getOverallActions())
|
||||
.setOverallArtifacts(report.getOverallArtifacts())
|
||||
.setOverallArtifactVolumeInBytes(report.getOverallArtifactVolumeInBytes())
|
||||
.setOverallTargets(report.getOverallTargets()).setOverallTenants(report.getTenants().size());
|
||||
|
||||
result.setTenantStats(
|
||||
report.getTenants().stream().map(SystemManagementResource::convertTenant).collect(Collectors.toList()));
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
private static SystemTenantServiceUsage convertTenant(final TenantUsage tenant) {
|
||||
final SystemTenantServiceUsage result = new SystemTenantServiceUsage(tenant.getTenantName());
|
||||
result.setActions(tenant.getActions());
|
||||
result.setArtifacts(tenant.getArtifacts());
|
||||
result.setOverallArtifactVolumeInBytes(tenant.getOverallArtifactVolumeInBytes());
|
||||
result.setTargets(tenant.getTargets());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all caches.
|
||||
*
|
||||
* @return a list of caches for all tenants
|
||||
*/
|
||||
@Override
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
|
||||
public ResponseEntity<Collection<SystemCache>> getCaches() {
|
||||
final Collection<String> cacheNames = cacheManager.getCacheNames();
|
||||
return ResponseEntity
|
||||
.ok(cacheNames.stream().map(cacheManager::getCache).map(this::cacheRest).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates all caches for all tenants.
|
||||
*
|
||||
* @return a list of cache names which has been invalidated
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
|
||||
@Override
|
||||
public ResponseEntity<Collection<String>> invalidateCaches() {
|
||||
final Collection<String> cacheNames = cacheManager.getCacheNames();
|
||||
LOGGER.info("Invalidating caches {}", cacheNames);
|
||||
cacheNames.forEach(cacheName -> cacheManager.getCache(cacheName).clear());
|
||||
return ResponseEntity.ok(cacheNames);
|
||||
}
|
||||
|
||||
private SystemCache cacheRest(final Cache cache) {
|
||||
final Object nativeCache = cache.getNativeCache();
|
||||
if (nativeCache instanceof com.google.common.cache.Cache) {
|
||||
return guavaCache(cache, nativeCache);
|
||||
} else {
|
||||
return new SystemCache(cache.getName(), Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private SystemCache guavaCache(final Cache cache, final Object nativeCache) {
|
||||
final com.google.common.cache.Cache<Object, Object> guavaCache = (com.google.common.cache.Cache<Object, Object>) nativeCache;
|
||||
final List<String> keys = guavaCache.asMap().keySet().stream().map(key -> key.toString())
|
||||
.collect(Collectors.toList());
|
||||
return new SystemCache(cache.getName(), keys);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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.system.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.system.json.model.system.SystemTenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
public class SystemMapper {
|
||||
|
||||
private SystemMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tenantConfigurationManagement
|
||||
* instance of TenantConfigurationManagement
|
||||
* @return a map of all existing configuration values
|
||||
*/
|
||||
public static Map<String, SystemTenantConfigurationValue> toResponse(
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
|
||||
final Map<String, SystemTenantConfigurationValue> configurationMap = new HashMap<>();
|
||||
|
||||
for (final TenantConfigurationKey key : TenantConfigurationKey.values()) {
|
||||
configurationMap.put(key.getKeyName(),
|
||||
toResponse(key.getKeyName(), tenantConfigurationManagement.getConfigurationValue(key)));
|
||||
}
|
||||
|
||||
return configurationMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* maps a TenantConfigurationValue from the repository model to a
|
||||
* SystemTenantConfigurationValue, the RESTful model.
|
||||
*
|
||||
* @param repoConfValue
|
||||
* configuration value as repository model
|
||||
* @return configuration value as RESTful model
|
||||
*/
|
||||
public static SystemTenantConfigurationValue toResponse(final String key,
|
||||
final TenantConfigurationValue<?> repoConfValue) {
|
||||
final SystemTenantConfigurationValue restConfValue = new SystemTenantConfigurationValue();
|
||||
|
||||
restConfValue.setValue(repoConfValue.getValue());
|
||||
restConfValue.setGlobal(repoConfValue.isGlobal());
|
||||
restConfValue.setCreatedAt(repoConfValue.getCreatedAt());
|
||||
restConfValue.setCreatedBy(repoConfValue.getCreatedBy());
|
||||
restConfValue.setLastModifiedAt(repoConfValue.getLastModifiedAt());
|
||||
restConfValue.setLastModifiedBy(repoConfValue.getLastModifiedBy());
|
||||
|
||||
restConfValue.add(linkTo(methodOn(SystemResource.class).getConfigurationValue(key)).withRel("self"));
|
||||
|
||||
return restConfValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* 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.system.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.system.json.model.system.SystemTenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.system.json.model.system.SystemTenantConfigurationValueRequest;
|
||||
import org.eclipse.hawkbit.system.rest.api.SystemRestApi;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling tenant specific configuration operations.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
public class SystemResource implements SystemRestApi {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SystemResource.class);
|
||||
|
||||
@Autowired
|
||||
private TenantConfigurationManagement tenantConfigurationManagement;
|
||||
|
||||
@Override
|
||||
public ResponseEntity<ResourceSupport> getSystem() {
|
||||
final ResourceSupport resourceSupport = new ResourceSupport();
|
||||
resourceSupport.add(linkTo(methodOn(SystemResource.class).getSystemConfiguration()).withRel("configs"));
|
||||
return ResponseEntity.ok(resourceSupport);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a Map of all configuration values.
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<Map<String, SystemTenantConfigurationValue>> getSystemConfiguration() {
|
||||
return new ResponseEntity<>(SystemMapper.toResponse(tenantConfigurationManagement), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the DELETE request of deleting a tenant specific configuration
|
||||
* value within SP.
|
||||
*
|
||||
* @param keyName
|
||||
* the Name of the configuration key
|
||||
* @return If the given configuration value exists and could be deleted Http
|
||||
* OK. In any failure the JsonResponseExceptionHandler is handling
|
||||
* the response.
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteConfigurationValue(final String keyName) {
|
||||
|
||||
final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName);
|
||||
|
||||
tenantConfigurationManagement.deleteConfiguration(configKey);
|
||||
|
||||
LOG.debug("{} config value deleted, return status {}", keyName, HttpStatus.OK);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the GET request of deleting a tenant specific configuration value
|
||||
* within SP.
|
||||
*
|
||||
* @param keyName
|
||||
* the Name of the configuration key
|
||||
* @return If the given configuration value exists and could be get Http OK.
|
||||
* In any failure the JsonResponseExceptionHandler is handling the
|
||||
* response.
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<SystemTenantConfigurationValue> getConfigurationValue(final String keyName) {
|
||||
|
||||
final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName);
|
||||
|
||||
LOG.debug("{} config value getted, return status {}", keyName, HttpStatus.OK);
|
||||
return new ResponseEntity<>(SystemMapper.toResponse(configKey.getKeyName(),
|
||||
tenantConfigurationManagement.getConfigurationValue(configKey)), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the GET request of deleting a tenant specific configuration value
|
||||
* within SP.
|
||||
*
|
||||
* @param keyName
|
||||
* the Name of the configuration key
|
||||
* @param configurationValueRest
|
||||
* the new value for the configuration
|
||||
* @return If the given configuration value exists and could be get Http OK.
|
||||
* In any failure the JsonResponseExceptionHandler is handling the
|
||||
* response.
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<SystemTenantConfigurationValue> updateConfigurationValue(final String keyName,
|
||||
final SystemTenantConfigurationValueRequest configurationValueRest) {
|
||||
|
||||
final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName);
|
||||
|
||||
final TenantConfigurationValue<Object> updatedValue = tenantConfigurationManagement
|
||||
|
||||
.addOrUpdateConfiguration(configKey, configurationValueRest.getValue());
|
||||
return new ResponseEntity<>(SystemMapper.toResponse(keyName, updatedValue), HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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.system.rest.resource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultHandler;
|
||||
import org.springframework.test.web.servlet.result.PrintingResultHandler;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
public abstract class MockMvcResultPrinter {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MockMvcResultPrinter.class);
|
||||
|
||||
private MockMvcResultPrinter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Print {@link MvcResult} details to the "standard" output stream.
|
||||
*/
|
||||
public static ResultHandler print() {
|
||||
return new ConsolePrintingResultHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link PrintingResultHandler} that writes to the "standard" output
|
||||
* stream
|
||||
*/
|
||||
private static class ConsolePrintingResultHandler extends PrintingResultHandler {
|
||||
|
||||
public ConsolePrintingResultHandler() {
|
||||
super(new ResultValuePrinter() {
|
||||
|
||||
@Override
|
||||
public void printHeading(final String heading) {
|
||||
LOG.debug(String.format("%20s:", heading));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printValue(final String label, Object value) {
|
||||
if (value != null && value.getClass().isArray()) {
|
||||
value = CollectionUtils.arrayToList(value);
|
||||
}
|
||||
LOG.debug(String.format("%20s = %s", label, value));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.system.rest.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* Utility additions for the REST API tests.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class ResourceUtility {
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
static ExceptionInfo convertException(final String jsonExceptionResponse)
|
||||
throws JsonParseException, JsonMappingException, IOException {
|
||||
return mapper.readValue(jsonExceptionResponse, ExceptionInfo.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* 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.system.rest.resource;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB;
|
||||
import org.eclipse.hawkbit.TestDataUtil;
|
||||
import org.eclipse.hawkbit.WithSpringAuthorityRule;
|
||||
import org.eclipse.hawkbit.WithUser;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Features("Component Tests - System API")
|
||||
@Stories("System Management Resource")
|
||||
public class SystemManagementResourceTest extends AbstractIntegrationTestWithMongoDB {
|
||||
|
||||
@Test
|
||||
@WithUser(tenantId = "mytenant", authorities = { SpPermission.SYSTEM_ADMIN })
|
||||
@Description("Tests that the system is able to collect statistics for the entire system.")
|
||||
public void collectSystemStatistics() throws Exception {
|
||||
createTestTenantsForSystemStatistics(2, 2000, 100, 2);
|
||||
|
||||
mvc.perform(get("/system/admin/usage").accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(jsonPath("$tenantStats.[?(@.tenantName==tenant0)][0].targets", equalTo(100)))
|
||||
.andExpect(jsonPath("$tenantStats.[?(@.tenantName==tenant0)][0].overallArtifactVolumeInBytes",
|
||||
equalTo(2000)))
|
||||
.andExpect(jsonPath("$tenantStats.[?(@.tenantName==tenant0)][0].artifacts", equalTo(1)))
|
||||
.andExpect(jsonPath("$tenantStats.[?(@.tenantName==tenant0)][0].actions", equalTo(200)))
|
||||
.andExpect(jsonPath("$overallTargets", equalTo(200)))
|
||||
.andExpect(jsonPath("$overallArtifacts", equalTo(2)))
|
||||
.andExpect(jsonPath("$overallArtifactVolumeInBytes", equalTo(4000)))
|
||||
.andExpect(jsonPath("$overallActions", equalTo(400)))
|
||||
.andExpect(jsonPath("$overallTenants", equalTo(4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(tenantId = "mytenant", authorities = { SpPermission.DELETE_TARGET, SpPermission.DELETE_REPOSITORY,
|
||||
SpPermission.CREATE_REPOSITORY, SpPermission.READ_REPOSITORY })
|
||||
@Description("Tests that the system is not able to collect statistics for the entire system if the .")
|
||||
public void collectSystemStatisticsWithMissingPermissionFails() throws Exception {
|
||||
|
||||
mvc.perform(get("/system/admin/usage").accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(tenantId = "mytenant", allSpPermissions = true)
|
||||
@Description("Tests that a tenant can be deletd by API.")
|
||||
public void deleteTenant() throws Exception {
|
||||
|
||||
final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement,
|
||||
distributionSetManagement);
|
||||
|
||||
assertThat(distributionSetManagement.findDistributionSetById(dsA.getId())).isNotNull();
|
||||
|
||||
mvc.perform(delete("/system/admin/tenants/mytenant")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
assertThat(distributionSetManagement.findDistributionSetById(dsA.getId())).isNull();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(tenantId = "mytenant", authorities = { SpPermission.DELETE_TARGET, SpPermission.DELETE_REPOSITORY,
|
||||
SpPermission.CREATE_REPOSITORY, SpPermission.READ_REPOSITORY })
|
||||
@Description("Tenant deletion is only possible for SYSTEM_ADMINs. Repository or target delete is not sufficient.")
|
||||
public void deleteTenantFailsMissingPermission() throws Exception {
|
||||
|
||||
final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement,
|
||||
distributionSetManagement);
|
||||
assertThat(distributionSetManagement.findDistributionSetById(dsA.getId())).isNotNull();
|
||||
|
||||
mvc.perform(delete("/system/admin/tenants/mytenant")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isForbidden());
|
||||
|
||||
assertThat(distributionSetManagement.findDistributionSetById(dsA.getId())).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCachesReturnStatus200() throws Exception {
|
||||
mvc.perform(get("/system/admin/caches")).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidateCachesReturnStatus200() throws Exception {
|
||||
mvc.perform(delete("/system/admin/caches")).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
private byte[] createTestTenantsForSystemStatistics(final int tenants, final int artifactSize, final int targets,
|
||||
final int updates) throws Exception {
|
||||
final Random randomgen = new Random();
|
||||
final byte random[] = new byte[artifactSize];
|
||||
randomgen.nextBytes(random);
|
||||
|
||||
for (int i = 0; i < tenants; i++) {
|
||||
final String tenantname = "tenant" + i;
|
||||
securityRule.runAs(WithSpringAuthorityRule.withUserAndTenant("bumlux", tenantname), () -> {
|
||||
systemManagement.getTenantMetadata(tenantname);
|
||||
if (artifactSize > 0) {
|
||||
createTestArtifact(random);
|
||||
createDeletedTestArtifact(random);
|
||||
}
|
||||
if (targets > 0) {
|
||||
final List<Target> createdTargets = createTestTargets(targets);
|
||||
if (updates > 0) {
|
||||
for (int x = 0; x < updates; x++) {
|
||||
final DistributionSet ds = TestDataUtil.generateDistributionSet("to be deployed" + x,
|
||||
softwareManagement, distributionSetManagement, true);
|
||||
|
||||
deploymentManagement.assignDistributionSet(ds, createdTargets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
return random;
|
||||
}
|
||||
|
||||
private List<Target> createTestTargets(final int targets) {
|
||||
return targetManagement
|
||||
.createTargets(TestDataUtil.buildTargetFixtures(targets, "testTargetOfTenant", "testTargetOfTenant"));
|
||||
}
|
||||
|
||||
private void createTestArtifact(final byte[] random) {
|
||||
SoftwareModule sm = new SoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1",
|
||||
"version 1", null, null);
|
||||
sm = softwareModuleRepository.save(sm);
|
||||
|
||||
artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), sm.getId(), "file1", false);
|
||||
}
|
||||
|
||||
private void createDeletedTestArtifact(final byte[] random) {
|
||||
final DistributionSet ds = TestDataUtil.generateDistributionSet("deleted garbage", softwareManagement,
|
||||
distributionSetManagement, true);
|
||||
ds.getModules().stream().forEach(module -> {
|
||||
artifactManagement.createLocalArtifact(new ByteArrayInputStream(random), module.getId(), "file1", false);
|
||||
softwareManagement.deleteSoftwareModule(module);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* 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.system.rest.resource;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.eclipse.hawkbit.AbstractIntegrationTest;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
|
||||
import org.eclipse.hawkbit.system.rest.api.SystemRestConstant;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Component Tests - System RESTful API")
|
||||
@Stories("ConfigurationResource")
|
||||
public class SystemResourceTest extends AbstractIntegrationTest {
|
||||
|
||||
private static String BASE_JSON_REQUEST_STRING = "{\"value\":\"%s\"}";
|
||||
|
||||
@Test
|
||||
@Description("perform a GET request on all existing configurations.")
|
||||
public void getConfigurationValues() throws Exception {
|
||||
|
||||
final ResultActions resultActions = mvc.perform(get(SystemRestConstant.SYSTEM_V1_REQUEST_MAPPING + "/configs/"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.*", hasSize(TenantConfigurationKey.values().length)));
|
||||
|
||||
for (final TenantConfigurationKey key : TenantConfigurationKey.values()) {
|
||||
|
||||
final TenantConfigurationValue<?> confValue = tenantConfigurationManagement.getConfigurationValue(key);
|
||||
resultActions.andExpect(jsonPath("$.['" + key.getKeyName() + "'].value", equalTo(confValue.getValue())))
|
||||
.andExpect(jsonPath("$.['" + key.getKeyName() + "'].global", equalTo(confValue.isGlobal())));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("perform a GET request on a existing configuration key.")
|
||||
public void getConfigurationValue() throws Exception {
|
||||
|
||||
final TenantConfigurationKey key = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME;
|
||||
final String notGlobalValue = "notTheGlobalHeaderAuthoryName";
|
||||
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(key, notGlobalValue);
|
||||
|
||||
mvc.perform(get(SystemRestConstant.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}/", key.getKeyName()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("value", equalTo(notGlobalValue))).andExpect(jsonPath("global", equalTo(false)))
|
||||
.andExpect(jsonPath("createdAt", notNullValue())).andExpect(jsonPath("createdBy", notNullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("perform a PUT request on a existing configuration key with a valid value.")
|
||||
public void putConfigurationValue() throws Exception {
|
||||
|
||||
final TenantConfigurationKey key = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME;
|
||||
final String testValue = "12:12:12";
|
||||
|
||||
mvc.perform(put(SystemRestConstant.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}/", key.getKeyName())
|
||||
.content(String.format(BASE_JSON_REQUEST_STRING, testValue)).contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).getValue())
|
||||
.isEqualTo(testValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("perform a DELETE request on a existing configuration key.")
|
||||
public void deleteConfigurationValue() throws Exception {
|
||||
|
||||
final TenantConfigurationKey key = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME;
|
||||
final String notGlobalValue = "notTheGlobalHeaderAuthoryName";
|
||||
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(key, notGlobalValue);
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).isGlobal()).isEqualTo(false);
|
||||
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).getValue())
|
||||
.isEqualTo(notGlobalValue);
|
||||
|
||||
mvc.perform(delete(SystemRestConstant.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}/", key.getKeyName()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNoContent());
|
||||
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).isGlobal()).isEqualTo(true);
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).getValue())
|
||||
.isNotEqualTo(notGlobalValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("perform a (put) request on a not existing configuration key.")
|
||||
public void putInvalidConfigurationKey() throws Exception {
|
||||
|
||||
final String notExistingKey = "notExistingKey";
|
||||
final String testValue = "12:12:12";
|
||||
|
||||
final MvcResult mvcResult = mvc
|
||||
.perform(put(SystemRestConstant.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}", notExistingKey)
|
||||
.content(String.format(BASE_JSON_REQUEST_STRING, testValue))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()).andReturn();
|
||||
|
||||
// verify response json exception message
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility
|
||||
.convertException(mvcResult.getResponse().getContentAsString());
|
||||
assertThat(exceptionInfo.getErrorCode()).isEqualTo(SpServerError.SP_CONFIGURATION_KEY_INVALID.getKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("perform a put request with a not matching configuration value.")
|
||||
public void putInvalidConfigurationValue() throws Exception {
|
||||
|
||||
final TenantConfigurationKey key = TenantConfigurationKey.POLLING_TIME_INTERVAL;
|
||||
final String testValue = "invalidFormattedDuration";
|
||||
|
||||
final MvcResult mvcResult = mvc
|
||||
.perform(put(SystemRestConstant.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}", key.getKeyName())
|
||||
.content(String.format(BASE_JSON_REQUEST_STRING, testValue))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()).andReturn();
|
||||
|
||||
// verify response json exception message
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility
|
||||
.convertException(mvcResult.getResponse().getContentAsString());
|
||||
assertThat(exceptionInfo.getErrorCode()).isEqualTo(SpServerError.SP_CONFIGURATION_VALUE_INVALID.getKey());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
# used if IM profile is disabled
|
||||
security.ignored=true
|
||||
|
||||
# IM required for integration tests
|
||||
spring.profiles.active=im,suiteembedded,artifactrepository,redis
|
||||
|
||||
server.port=12222
|
||||
|
||||
spring.data.mongodb.uri=mongodb://localhost/spArtifactRepository${random.value}
|
||||
spring.data.mongodb.port=28017
|
||||
|
||||
|
||||
# supported: H2, MYSQL
|
||||
hawkbit.server.database=H2
|
||||
hawkbit.server.database.env=TEST
|
||||
spring.main.show_banner=false
|
||||
|
||||
hawkbit.server.ddi.security.authentication.header=true
|
||||
|
||||
hawkbit.server.artifact.repo.upload.maxFileSize=5MB
|
||||
|
||||
hawkbit.server.security.dos.maxStatusEntriesPerAction=100
|
||||
|
||||
hawkbit.server.security.dos.maxAttributeEntriesPerTarget=10
|
||||
|
||||
spring.jpa.database=${hawkbit.server.database}
|
||||
#spring.jpa.show-sql=true
|
||||
|
||||
|
||||
flyway.sqlMigrationSuffix=${spring.jpa.database}.sql
|
||||
|
||||
# effective DB setting
|
||||
spring.datasource.url=${${hawkbit.server.database}.spring.datasource.url}
|
||||
spring.datasource.driverClassName=${${hawkbit.server.database}.spring.datasource.driverClassName}
|
||||
spring.datasource.username=${${hawkbit.server.database}.spring.datasource.username}
|
||||
spring.datasource.password=${${hawkbit.server.database}.spring.datasource.password}
|
||||
|
||||
# H2
|
||||
##;AUTOCOMMIT=ON
|
||||
H2.spring.datasource.url=jdbc:h2:mem:sp-db;DB_CLOSE_ON_EXIT=FALSE
|
||||
#H2.spring.datasource.url=jdbc:h2:./db/sp-db;AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=FALSE;MVCC=TRUE
|
||||
H2.spring.datasource.driverClassName=org.h2.Driver
|
||||
H2.spring.datasource.username=sa
|
||||
H2.spring.datasource.password=sa
|
||||
|
||||
# MYSQL
|
||||
MYSQL.spring.datasource.url=jdbc:mysql://localhost:3306/sp_test
|
||||
MYSQL.spring.datasource.driverClassName=org.mariadb.jdbc.Driver
|
||||
MYSQL.spring.datasource.username=root
|
||||
MYSQL.spring.datasource.password=
|
||||
|
||||
# SP Controller configuration
|
||||
hawkbit.controller.pollingTime=00:01:00
|
||||
hawkbit.controller.pollingOverdueTime=00:01:00
|
||||
Reference in New Issue
Block a user