hawkBit rest docs (management & DDI API) (#688)

* hawkBit REST docs.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fiy gitignore.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Add to website.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Switch to generated docs.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix typos.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Review findings.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Otimizations.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Revert accidental checkin.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Add security link.
This commit is contained in:
Kai Zimmermann
2018-05-24 16:10:01 +02:00
committed by GitHub
parent 7126d68f31
commit 428e3af2bc
244 changed files with 11636 additions and 430 deletions

View File

@@ -0,0 +1,129 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.ddi.documentation;
/**
* Model properties for the DDI API documentation.
*/
final class DdiApiModelProperties {
// Direct Device Integration API
static final String CONTROLLER_ID = "id of the controller";
static final String TARGET_TIME = "time on the target device";
static final String TARGET_STATUS = "target action status";
static final String TARGET_EXEC_STATUS = "status of the action execution";
static final String TARGET_RESULT_VALUE = "result of the action execution";
static final String TARGET_RESULT_DETAILS = "List of details message information";
static final String TARGET_RESULT_FINISHED = "defined status of the result";
static final String TARGET_RESULT_PROGRESS = "progress assumption of the device";
static final String TARGET_PROGRESS_CNT = "current progress level";
static final String TARGET_PROGRESS_OF = "assumption concerning max progress level";
static final String ACTION_ID = "id of the action";
static final String CANCEL_ACTION = "action that needs to be canceled";
static final String ACTION_ID_CANCELED = "id of the action that needs to be canceled (typically identical to id field on the cancel action itself)";
static final String ARTIFACT_HTTPS_HASHES_MD5SUM_LINK = "HTTPs Download resource for MD5SUM file is an optional auto generated artifact that is especially useful for "
+ "Linux based devices on order to check artifact consistency after download by using the md5sum "
+ "command line tool. The MD5 and SHA1 are in addition available as metadata in the deployment command itself.";
static final String ARTIFACT_HTTP_HASHES_MD5SUM_LINK = "HTTP Download resource for MD5SUM file is an optional auto generated artifact that is especially useful for "
+ "Linux based devices on order to check artifact consistency after download by using the md5sum "
+ "command line tool. The MD5 and SHA1 are in addition available as metadata in the deployment command itself. "
+ "(note: anonymous download needs to be enabled on the service account for non-TLS access)";
static final String ARTIFACT_HTTPS_DOWNLOAD_LINK_BY_CONTROLLER = "HTTPs Download resource for artifacts. The resource supports partial download "
+ "as specified by RFC7233 (range requests). Keep in mind that the target "
+ "needs to have the artifact assigned in order to be granted permission to download.";
static final String ARTIFACT_HTTP_DOWNLOAD_LINK_BY_CONTROLLER = "HTTP Download resource for artifacts. The resource supports partial download "
+ "as specified by RFC7233 (range requests). Keep in mind that the target "
+ "needs to have the artifact assigned in order to be granted permission to download. "
+ "(note: anonymous download needs to be enabled on the service account for non-TLS access)";
static final String CHUNK_TYPE = "Type of the chunk, e.g. firmware, bundle, app. In update server mapped to Software Module Type.";
static final String SOFTWARE_MODUL_TYPE = "type of the software module, e.g. firmware, bundle, app";
static final String SOFTWARE_MODULE_VERSION = "version of the software module";
static final String SOFTWARE_MODULE_NAME = "name of the software module";
static final String SOFTWARE_MODULE_ARTIFACT_LINKS = "artifact links of the software module";
static final String SOFTWARE_MODUL_ID = "id of the software module";
static final String CHUNK_VERSION = "software version of the chunk";
static final String CHUNK_NAME = "name of the chunk";
static final String CHUNK_META_DATA = "meta data of the respective software module that has been marked with 'target visible'";
static final String CHUNK_META_DATA_KEY = "key of meta data entry";
static final String CHUNK_META_DATA_VALUE = "value of meta data entry";
static final String ARTIFACTS = "list of artifacts";
static final String TARGET_CONFIGURATION = "target configuration setup by the server";
static final String TARGET_POLL_TIME = "suggested sleep time between polls";
static final String TARGET_OPEN_ACTIONS = "Open Actions that the server has for the target";
static final String TARGET_SLEEP = "sleep time in HH:MM:SS notation";
static final String DEPLOYMENT = "Detailed deployment operation";
static final String CANCEL = "Detailed cancel operation of a deployment.";
static final String HANDLING_DOWNLOAD = "handling for the download part of the provisioning process ('skip': do not download yet, 'attempt': server asks to download, 'forced': server requests immediate download)";
static final String HANDLING_UPDATE = "handling for the update part of the provisioning process ('skip': do not update yet, 'attempt': server asks to update, 'forced': server requests immediate update)";
static final String MAINTENANCE_WINDOW = "separation of download and installation by defining a maintenance window for the installation. Status shows if currently in a window.";
static final String CHUNK = "Software chunks of an update. In server mapped by Software Module.";
static final String SOFTWARE_MODUL = "software modules of an update";
static final String ARTIFACT = "artifact modules of an update";
static final String FILENAME = "file name of artifact";
static final String TARGET_CONFIG_DATA = "configuration data as key/value list";
static final String ARTIFACT_HASHES_SHA1 = "SHA1 hash of the artifact in Base 16 format";
static final String ARTIFACT_HASHES_MD5 = "MD5 hash of the artifact";
static final String ARTIFACT_SIZE = "size of the artifact";
static final String ACTION_HISTORY = "Optional GET parameter to retrieve a given number of messages which are previously provided by the device. "
+ "Useful if the devices sent state information to the feedback channel and never stored them locally.";
static final String ACTION_HISTORY_RESP = "Current deployment state.";
static final String ACTION_HISTORY_RESP_STATUS = "Status of the deployment based on previous feedback by the device.";
static final String ACTION_HISTORY_RESP_MESSAGES = "Messages are previously sent to the feedback channel in LIFO order by the device.";
static final String UPDATE_MODE = "Optional parameter to specify the update mode that should be applied when updating target attributes. "
+ "Valid values are 'merge', 'replace', and 'remove'. Defaults to 'merge'.";
}

View File

@@ -0,0 +1,459 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.ddi.documentation;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.restdocs.snippet.Attributes.key;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.Before;
import org.junit.Test;
import org.springframework.hateoas.MediaTypes;
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;
/**
* Documentation generation for Direct Device Integration API.
*
*/
@Features("Documentation Verfication - Direct Device Integration API")
@Stories("Root Resource")
public class RootControllerDocumentationTest extends AbstractApiRestDocumentation {
private static final String CONTROLLER_ID = "CONTROLLER_ID";
@Override
@Before
public void setUp() {
host = "ddi-api.host";
resourceName = "rootcontroller";
super.setUp();
}
@Test
@Description("This base resource can be regularly polled by the controller on the provisiong target or device "
+ "in order to retrieve actions that need to be executed. In this case including a config pull request and a deployment. The resource supports Etag based modification "
+ "checks in order to save traffic.")
@WithUser(tenantId = "TENANT_ID", authorities = "ROLE_CONTROLLER", allSpPermissions = true)
public void getControllerBaseWithOpenDeplyoment() throws Exception {
final DistributionSet set = testdataFactory.createDistributionSet("one");
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
deploymentManagement.assignDistributionSet(set.getId(), Arrays.asList(target.getTargetWithActionType()));
mockMvc.perform(get(DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}",
tenantAware.getCurrentTenant(), target.getControllerId()).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(parameterWithName("tenant").description(ApiModelPropertiesGeneric.TENANT),
parameterWithName("controllerId").description(DdiApiModelProperties.CONTROLLER_ID)),
responseFields(
fieldWithPath("config.polling").description(DdiApiModelProperties.TARGET_POLL_TIME),
fieldWithPath("config.polling.sleep").description(DdiApiModelProperties.TARGET_SLEEP),
fieldWithPath("_links").description(DdiApiModelProperties.TARGET_OPEN_ACTIONS),
fieldWithPath("_links.deploymentBase").description(DdiApiModelProperties.DEPLOYMENT),
fieldWithPath("_links.configData")
.description(DdiApiModelProperties.TARGET_CONFIG_DATA))));
}
@Test
@Description("This base resource can be regularly polled by the controller on the provisiong target or device "
+ "in order to retrieve actions that need to be executed. In this case including a config pull request and a cancellation. "
+ "Note: as with deployments the cancel action has to be confirmed or rejected in order to move on to the next action.")
@WithUser(tenantId = "TENANT_ID", authorities = "ROLE_CONTROLLER", allSpPermissions = true)
public void getControllerBaseWithOpenDeploymentCancellation() throws Exception {
final DistributionSet set = testdataFactory.createDistributionSet("one");
final DistributionSet setTwo = testdataFactory.createDistributionSet("two");
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
deploymentManagement.assignDistributionSet(set.getId(), Arrays.asList(target.getTargetWithActionType()));
deploymentManagement.assignDistributionSet(setTwo.getId(), Arrays.asList(target.getTargetWithActionType()));
mockMvc.perform(get(DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}",
tenantAware.getCurrentTenant(), target.getControllerId()).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(parameterWithName("tenant").description(ApiModelPropertiesGeneric.TENANT),
parameterWithName("controllerId").description(DdiApiModelProperties.CONTROLLER_ID)),
responseFields(
fieldWithPath("config.polling").description(DdiApiModelProperties.TARGET_POLL_TIME),
fieldWithPath("config.polling.sleep").description(DdiApiModelProperties.TARGET_SLEEP),
fieldWithPath("_links").description(DdiApiModelProperties.TARGET_OPEN_ACTIONS),
fieldWithPath("_links.cancelAction").description(DdiApiModelProperties.DEPLOYMENT),
fieldWithPath("_links.configData")
.description(DdiApiModelProperties.TARGET_CONFIG_DATA))));
}
@Test
@Description("The SP server might cancel an operation, e.g. an unfinished update has a sucessor. "
+ "It is up to the provisiong target to decide either to accept the cancelation or reject it.")
@WithUser(tenantId = "TENANT_ID", authorities = "ROLE_CONTROLLER", allSpPermissions = true)
public void getControllerCancelAction() throws Exception {
final DistributionSet set = testdataFactory.createDistributionSet("one");
set.getModules().forEach(module -> {
final byte random[] = RandomStringUtils.random(5).getBytes();
artifactManagement.create(new ByteArrayInputStream(random), module.getId(), "binary.tgz", false, 0);
artifactManagement.create(new ByteArrayInputStream(random), module.getId(), "file.signature", false, 0);
});
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
final Long actionId = deploymentManagement
.assignDistributionSet(set.getId(), Arrays.asList(target.getTargetWithActionType())).getActions()
.get(0);
final Action cancelAction = deploymentManagement.cancelAction(actionId);
mockMvc.perform(
get(DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/" + DdiRestConstants.CANCEL_ACTION
+ "/{actionId}", tenantAware.getCurrentTenant(), target.getControllerId(), cancelAction.getId())
.accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(parameterWithName("tenant").description(ApiModelPropertiesGeneric.TENANT),
parameterWithName("controllerId").description(DdiApiModelProperties.CONTROLLER_ID),
parameterWithName("actionId").description(DdiApiModelProperties.ACTION_ID_CANCELED)),
responseFields(fieldWithPath("id").description(DdiApiModelProperties.ACTION_ID),
fieldWithPath("cancelAction").description(DdiApiModelProperties.CANCEL_ACTION),
fieldWithPath("cancelAction.stopId")
.description(DdiApiModelProperties.ACTION_ID_CANCELED)
)));
}
@Test
@Description("It is up to the device to decided how much intermediate feedback is "
+ "provided. However, the action will be kept open until the controller on the device reports a "
+ "finished (either successfull or error) or rejects the oprtioan, e.g. the canceled actions have been started already.")
@WithUser(tenantId = "TENANT_ID", authorities = "ROLE_CONTROLLER", allSpPermissions = true)
public void postCancelActionFeedback() throws Exception {
final DistributionSet set = testdataFactory.createDistributionSet("one");
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
final Long actionId = deploymentManagement
.assignDistributionSet(set.getId(), Arrays.asList(target.getTargetWithActionType())).getActions()
.get(0);
final Action cancelAction = deploymentManagement.cancelAction(actionId);
mockMvc.perform(post(
DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/" + DdiRestConstants.CANCEL_ACTION
+ "/{actionId}/feedback",
tenantAware.getCurrentTenant(), target.getControllerId(), cancelAction.getId()).content(
JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed", "Some feedback"))
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("tenant").description(ApiModelPropertiesGeneric.TENANT),
parameterWithName("controllerId").description(DdiApiModelProperties.CONTROLLER_ID),
parameterWithName("actionId").description(DdiApiModelProperties.ACTION_ID_CANCELED)),
requestFields(optionalRequestFieldWithPath("id").description(DdiApiModelProperties.ACTION_ID),
optionalRequestFieldWithPath("time").description(DdiApiModelProperties.TARGET_TIME),
requestFieldWithPath("status").description(DdiApiModelProperties.TARGET_STATUS),
requestFieldWithPath("status.execution")
.description(DdiApiModelProperties.TARGET_EXEC_STATUS).type("enum")
.attributes(key("value").value(
"['closed', 'proceeding', 'canceled','scheduled', 'rejected', 'resumed']")),
requestFieldWithPath("status.result")
.description(DdiApiModelProperties.TARGET_RESULT_VALUE),
requestFieldWithPath("status.result.finished")
.description(DdiApiModelProperties.TARGET_RESULT_FINISHED).type("enum")
.attributes(key("value").value("['success', 'failure', 'none']")),
optionalRequestFieldWithPath("status.details")
.description(DdiApiModelProperties.TARGET_RESULT_DETAILS))));
}
@Test
@Description("The usual behaviour is that when a new device resgisters at the server it is "
+ "requested to provide the meta information that will allow the server to identify the device on a "
+ "hardware level (e.g. hardware revision, mac address, serial number etc.).")
@WithUser(tenantId = "TENANT_ID", authorities = "ROLE_CONTROLLER", allSpPermissions = true)
public void putConfigData() throws Exception {
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
final Map<String, String> attributes = new HashMap<>();
attributes.put("hwRevision", "2");
attributes.put("VIN", "JH4TB2H26CC000000");
mockMvc.perform(
put(DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/" + DdiRestConstants.CONFIG_DATA_ACTION,
tenantAware.getCurrentTenant(), target.getControllerId())
.content(JsonBuilder.configData("", attributes, "closed", "merge"))
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("tenant").description(ApiModelPropertiesGeneric.TENANT),
parameterWithName("controllerId").description(DdiApiModelProperties.CONTROLLER_ID)),
requestFields(optionalRequestFieldWithPath("id").description(DdiApiModelProperties.ACTION_ID),
optionalRequestFieldWithPath("time").description(DdiApiModelProperties.TARGET_TIME),
requestFieldWithPath("status").description(DdiApiModelProperties.TARGET_STATUS),
requestFieldWithPath("status.execution")
.description(DdiApiModelProperties.TARGET_EXEC_STATUS).type("enum")
.attributes(key("value").value(
"['closed', 'proceeding', 'canceled','scheduled', 'rejected', 'resumed']")),
requestFieldWithPath("status.result")
.description(DdiApiModelProperties.TARGET_RESULT_VALUE),
requestFieldWithPath("status.result.finished")
.description(DdiApiModelProperties.TARGET_RESULT_FINISHED).type("enum")
.attributes(key("value").value("['success', 'failure', 'none']")),
optionalRequestFieldWithPath("status.details")
.description(DdiApiModelProperties.TARGET_RESULT_DETAILS),
requestFieldWithPath("data").description(DdiApiModelProperties.TARGET_CONFIG_DATA),
optionalRequestFieldWithPath("mode").description(DdiApiModelProperties.UPDATE_MODE)
.type("enum")
.attributes(key("value").value("['merge', 'replace', 'remove']")))));
}
@Test
@Description("Core resource for deployment operations. Contains all information necessary in order to execute the operation.")
@WithUser(tenantId = "TENANT_ID", authorities = "ROLE_CONTROLLER", allSpPermissions = true)
public void getControllerBasedeploymentAction() throws Exception {
final DistributionSet set = testdataFactory.createDistributionSet("one");
set.getModules().forEach(module -> {
final byte random[] = RandomStringUtils.random(5).getBytes();
artifactManagement.create(new ByteArrayInputStream(random), module.getId(), "binary.tgz", false, 0);
artifactManagement.create(new ByteArrayInputStream(random), module.getId(), "file.signature", false, 0);
});
softwareModuleManagement.createMetaData(
entityFactory.softwareModuleMetadata().create(set.getModules().iterator().next().getId())
.key("aMetadataKey").value("Metadata value as defined in software module").targetVisible(true));
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
final Long actionId = assignDistributionSetWithMaintenanceWindow(set.getId(), target.getControllerId(),
getTestSchedule(-5), getTestDuration(10), getTestTimeZone()).getActions().get(0);
controllerManagement.addInformationalActionStatus(
entityFactory.actionStatus().create(actionId).message("Started download").status(Status.DOWNLOAD));
controllerManagement.addInformationalActionStatus(entityFactory.actionStatus().create(actionId)
.message("Download failed. ErrorCode #5876745. Retry").status(Status.WARNING));
controllerManagement.addInformationalActionStatus(
entityFactory.actionStatus().create(actionId).message("Download done").status(Status.DOWNLOADED));
controllerManagement.addInformationalActionStatus(
entityFactory.actionStatus().create(actionId).message("Write firmware").status(Status.RUNNING));
controllerManagement.addInformationalActionStatus(
entityFactory.actionStatus().create(actionId).message("Reboot").status(Status.RUNNING));
mockMvc.perform(get(
DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/" + DdiRestConstants.DEPLOYMENT_BASE_ACTION
+ "/{actionId}?actionHistory=10",
tenantAware.getCurrentTenant(), target.getControllerId(), actionId).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(parameterWithName("tenant").description(ApiModelPropertiesGeneric.TENANT),
parameterWithName("controllerId").description(DdiApiModelProperties.CONTROLLER_ID),
parameterWithName("actionId").description(DdiApiModelProperties.ACTION_ID)),
requestParameters(
parameterWithName("actionHistory").description(DdiApiModelProperties.ACTION_HISTORY)),
responseFields(fieldWithPath("id").description(DdiApiModelProperties.ACTION_ID),
fieldWithPath("deployment").description(DdiApiModelProperties.DEPLOYMENT),
fieldWithPath("deployment.download")
.description(DdiApiModelProperties.HANDLING_DOWNLOAD).type("enum")
.attributes(key("value").value("['skip', 'attempt', 'forced']")),
fieldWithPath("deployment.update").description(DdiApiModelProperties.HANDLING_UPDATE)
.type("enum").attributes(key("value").value("['skip', 'attempt', 'forced']")),
fieldWithPath("deployment.maintenanceWindow")
.description(DdiApiModelProperties.MAINTENANCE_WINDOW).type("enum")
.attributes(key("value").value("['available', 'unavailable']")),
fieldWithPath("deployment.chunks").description(DdiApiModelProperties.CHUNK),
fieldWithPath("deployment.chunks[].metadata")
.description(DdiApiModelProperties.CHUNK_META_DATA),
fieldWithPath("deployment.chunks[].metadata[].key")
.description(DdiApiModelProperties.CHUNK_META_DATA_KEY),
fieldWithPath("deployment.chunks[].metadata[].value")
.description(DdiApiModelProperties.CHUNK_META_DATA_VALUE),
fieldWithPath("deployment.chunks[].part").description(DdiApiModelProperties.CHUNK_TYPE),
fieldWithPath("deployment.chunks[].name").description(DdiApiModelProperties.CHUNK_NAME),
fieldWithPath("deployment.chunks[].version")
.description(DdiApiModelProperties.CHUNK_VERSION),
fieldWithPath("deployment.chunks[].artifacts")
.description(DdiApiModelProperties.ARTIFACTS),
fieldWithPath("deployment.chunks[].artifacts[].filename")
.description(DdiApiModelProperties.ARTIFACTS),
fieldWithPath("deployment.chunks[].artifacts[].hashes")
.description(DdiApiModelProperties.ARTIFACTS),
fieldWithPath("deployment.chunks[].artifacts[].hashes.sha1")
.description(DdiApiModelProperties.ARTIFACT_HASHES_SHA1),
fieldWithPath("deployment.chunks[].artifacts[].hashes.md5")
.description(DdiApiModelProperties.ARTIFACT_HASHES_MD5),
fieldWithPath("deployment.chunks[].artifacts[].size")
.description(DdiApiModelProperties.ARTIFACT_SIZE),
fieldWithPath("deployment.chunks[].artifacts[]._links.download")
.description(DdiApiModelProperties.ARTIFACT_HTTPS_DOWNLOAD_LINK_BY_CONTROLLER),
fieldWithPath("deployment.chunks[].artifacts[]._links.md5sum")
.description(DdiApiModelProperties.ARTIFACT_HTTPS_HASHES_MD5SUM_LINK),
fieldWithPath("deployment.chunks[].artifacts[]._links.download-http")
.description(DdiApiModelProperties.ARTIFACT_HTTP_DOWNLOAD_LINK_BY_CONTROLLER),
fieldWithPath("deployment.chunks[].artifacts[]._links.md5sum-http")
.description(DdiApiModelProperties.ARTIFACT_HTTP_HASHES_MD5SUM_LINK),
fieldWithPath("actionHistory").description(DdiApiModelProperties.ACTION_HISTORY_RESP),
fieldWithPath("actionHistory.status")
.description(DdiApiModelProperties.ACTION_HISTORY_RESP_STATUS),
fieldWithPath("actionHistory.messages")
.description(DdiApiModelProperties.ACTION_HISTORY_RESP_MESSAGES))));
}
@Test
@Description("Core resource for deployment operations. Contains all information necessary in order to execute the operation. Example with maintenance window where the device is requested to download only as it is not in the maintenance window yet.")
@WithUser(tenantId = "TENANT_ID", authorities = "ROLE_CONTROLLER", allSpPermissions = true)
public void getControllerBasedeploymentActionWithMaintenanceWindow() throws Exception {
final DistributionSet set = testdataFactory.createDistributionSet("one");
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
final Long actionId = assignDistributionSetWithMaintenanceWindow(set.getId(), target.getControllerId(),
getTestSchedule(2), getTestDuration(1), getTestTimeZone()).getActions().get(0);
mockMvc.perform(get(
DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/" + DdiRestConstants.DEPLOYMENT_BASE_ACTION
+ "/{actionId}?actionHistory=10",
tenantAware.getCurrentTenant(), target.getControllerId(), actionId).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(parameterWithName("tenant").description(ApiModelPropertiesGeneric.TENANT),
parameterWithName("controllerId").description(DdiApiModelProperties.CONTROLLER_ID),
parameterWithName("actionId").description(DdiApiModelProperties.ACTION_ID)),
requestParameters(
parameterWithName("actionHistory").description(DdiApiModelProperties.ACTION_HISTORY)),
responseFields(fieldWithPath("id").description(DdiApiModelProperties.ACTION_ID),
fieldWithPath("deployment").description(DdiApiModelProperties.DEPLOYMENT),
fieldWithPath("deployment.download")
.description(DdiApiModelProperties.HANDLING_DOWNLOAD),
fieldWithPath("deployment.update").description(DdiApiModelProperties.HANDLING_UPDATE)
.type("enum").attributes(key("value").value("['attempt', 'forced']")),
fieldWithPath("deployment.maintenanceWindow")
.description(DdiApiModelProperties.MAINTENANCE_WINDOW).type("enum")
.attributes(key("value").value("['available', 'unavailable']")),
fieldWithPath("deployment.chunks").description(DdiApiModelProperties.CHUNK),
fieldWithPath("deployment.chunks[].part").description(DdiApiModelProperties.CHUNK_TYPE),
fieldWithPath("deployment.chunks[].name").description(DdiApiModelProperties.CHUNK_NAME),
fieldWithPath("deployment.chunks[].version")
.description(DdiApiModelProperties.CHUNK_VERSION))));
}
@Test
@Description("Feedback channel. It is up to the device to decided how much intermediate feedback is "
+ "provided. However, the action will be kept open until the controller on the device reports a "
+ "finished (either successfull or error).")
@WithUser(tenantId = "TENANT_ID", authorities = "ROLE_CONTROLLER", allSpPermissions = true)
public void postBasedeploymentActionFeedback() throws Exception {
final DistributionSet set = testdataFactory.createDistributionSet("one");
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
final Long actionId = deploymentManagement
.assignDistributionSet(set.getId(), Arrays.asList(target.getTargetWithActionType())).getActions()
.get(0);
mockMvc.perform(post(DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/"
+ DdiRestConstants.DEPLOYMENT_BASE_ACTION + "/{actionId}/feedback", tenantAware.getCurrentTenant(),
target.getControllerId(), actionId)
.content(
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed", "Feddback message"))
.contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("tenant").description(ApiModelPropertiesGeneric.TENANT),
parameterWithName("controllerId").description(DdiApiModelProperties.CONTROLLER_ID),
parameterWithName("actionId").description(DdiApiModelProperties.ACTION_ID)),
requestFields(optionalRequestFieldWithPath("id").description(DdiApiModelProperties.ACTION_ID),
optionalRequestFieldWithPath("time").description(DdiApiModelProperties.TARGET_TIME),
requestFieldWithPath("status").description(DdiApiModelProperties.TARGET_STATUS),
requestFieldWithPath("status.execution")
.description(DdiApiModelProperties.TARGET_EXEC_STATUS).type("enum")
.attributes(key("value").value(
"['closed', 'proceeding', 'canceled','scheduled', 'rejected', 'resumed']")),
requestFieldWithPath("status.result")
.description(DdiApiModelProperties.TARGET_RESULT_VALUE),
requestFieldWithPath("status.result.finished")
.description(DdiApiModelProperties.TARGET_RESULT_FINISHED).type("enum")
.attributes(key("value").value("['success', 'failure', 'none']")),
optionalRequestFieldWithPath("status.result.progress")
.description(DdiApiModelProperties.TARGET_RESULT_PROGRESS),
optionalRequestFieldWithPath("status.details")
.description(DdiApiModelProperties.TARGET_RESULT_DETAILS))));
}
@Test
@Description("Returns all artifacts whichs is assigned to the software module."
+ "Can be usesfull for the target to double check that its current state matches with the targeted state.")
@WithUser(tenantId = "TENANT_ID", authorities = "ROLE_CONTROLLER", allSpPermissions = true)
public void getSoftwareModulesArtifacts() throws Exception {
final DistributionSet set = testdataFactory.createDistributionSet("");
final SoftwareModule module = (SoftwareModule) set.getModules().toArray()[0];
final byte random[] = RandomStringUtils.random(5).getBytes();
artifactManagement.create(new ByteArrayInputStream(random), module.getId(), "binaryFile", false, 0);
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
deploymentManagement.assignDistributionSet(set.getId(), Arrays.asList(target.getTargetWithActionType()));
mockMvc.perform(
get(DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/softwaremodules/{moduleId}/artifacts",
tenantAware.getCurrentTenant(), target.getControllerId(), module.getId())
.accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(parameterWithName("tenant").description(ApiModelPropertiesGeneric.TENANT),
parameterWithName("controllerId").description(DdiApiModelProperties.CONTROLLER_ID),
parameterWithName("moduleId").description(DdiApiModelProperties.SOFTWARE_MODUL_ID)),
responseFields(fieldWithPath("[]filename").description(DdiApiModelProperties.ARTIFACTS),
fieldWithPath("[]hashes").description(DdiApiModelProperties.ARTIFACTS),
fieldWithPath("[]hashes.sha1").description(DdiApiModelProperties.ARTIFACT_HASHES_SHA1),
fieldWithPath("[]hashes.md5").description(DdiApiModelProperties.ARTIFACT_HASHES_MD5),
fieldWithPath("[]size").description(DdiApiModelProperties.ARTIFACT_SIZE),
fieldWithPath("[]_links.download")
.description(DdiApiModelProperties.ARTIFACT_HTTPS_DOWNLOAD_LINK_BY_CONTROLLER),
fieldWithPath("[]_links.md5sum")
.description(DdiApiModelProperties.ARTIFACT_HTTPS_HASHES_MD5SUM_LINK),
fieldWithPath("[]_links.download-http")
.description(DdiApiModelProperties.ARTIFACT_HTTP_DOWNLOAD_LINK_BY_CONTROLLER),
fieldWithPath("[]_links.md5sum-http")
.description(DdiApiModelProperties.ARTIFACT_HTTP_HASHES_MD5SUM_LINK))));
}
}

View File

@@ -0,0 +1,294 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.documentation;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.restdocs.snippet.Attributes.key;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.ddi.rest.resource.DdiApiConfiguration;
import org.eclipse.hawkbit.mgmt.rest.resource.MgmtApiConfiguration;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
import org.eclipse.hawkbit.rest.util.FilterHttpResponse;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
import org.springframework.restdocs.payload.FieldDescriptor;
import org.springframework.restdocs.snippet.Snippet;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import ru.yandex.qatools.allure.annotations.Features;
/**
* Parent class for all Management API rest documentation classes.
*
*/
@Features("Documentation Verfication - API")
@SpringApplicationConfiguration(classes = { DdiApiConfiguration.class, MgmtApiConfiguration.class })
@TestPropertySource(locations = { "classpath:/updateserver-restdocumentation-test.properties" })
public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrationTest {
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("target/generated-snippets");
@Autowired
protected ObjectMapper objectMapper;
@Autowired
private FilterHttpResponse filterHttpResponse;
protected MockMvc mockMvc;
protected String resourceName = "output";
protected RestDocumentationResultHandler document;
protected String arrayPrefix;
protected String host = "management-api.host";
@Before
protected void setUp() {
this.document = document(resourceName + "/{method-name}", preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint()));
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(MockMvcRestDocumentation.documentationConfiguration(this.restDocumentation).uris()
.withScheme("https").withHost(host + ".com").withPort(443))
.alwaysDo(this.document).addFilter(filterHttpResponse).build();
arrayPrefix = "[]";
}
public static MyFieldFieldDesc requestFieldWithPath(final String path, final boolean mandatory) {
final MyFieldFieldDesc myFieldDesc = new MyFieldFieldDesc(path);
myFieldDesc.attributes(key("mandatory").value(mandatory ? "X" : ""));
// defaults
myFieldDesc.attributes(key("value").value(""));
return myFieldDesc;
}
public static MyFieldFieldDesc requestFieldWithPath(final String path) {
return requestFieldWithPath(path, true);
}
protected static MyFieldFieldDesc optionalRequestFieldWithPath(final String path) {
return requestFieldWithPath(path, false);
}
public static class MyFieldFieldDesc extends FieldDescriptor {
/**
* @param path
*/
protected MyFieldFieldDesc(final String path) {
super(path);
}
}
/**
* Wrapper for FieldDescriptor adding attribute with a key named value if
* not set.
*
* @param path
* @return FieldDescriptor with value key
*/
public static FieldDescriptor fieldWithPath(final String path) {
final MyFieldFieldDesc myFieldDesc = new MyFieldFieldDesc(path);
// defaults
myFieldDesc.attributes(key("value").value(""));
return myFieldDesc;
}
protected Target createTargetByGivenNameWithAttributes(final String name, final boolean inSync,
final boolean timeforced, final DistributionSet distributionSet) {
return createTargetByGivenNameWithAttributes(name, inSync, timeforced, distributionSet, null, null, null);
}
protected Target createTargetByGivenNameWithAttributes(final String name, final boolean inSync,
final boolean timeforced, final DistributionSet distributionSet, final String maintenanceWindowSchedule,
final String maintenanceWindowDuration, final String maintenanceWindowTimeZone) {
final Target savedTarget = targetManagement.create(entityFactory.target().create().controllerId(name)
.status(TargetUpdateStatus.UNKNOWN).address("http://192.168.0.1").description("My name is " + name)
.lastTargetQuery(System.currentTimeMillis()));
final List<Target> updatedTargets = maintenanceWindowSchedule == null
? assignWithoutMaintenanceWindow(distributionSet, savedTarget, timeforced)
: assignWithMaintenanceWindow(distributionSet, savedTarget, timeforced, maintenanceWindowSchedule,
maintenanceWindowDuration, maintenanceWindowTimeZone);
if (inSync) {
feedbackToByInSync(distributionSet);
}
return updatedTargets.get(0);
}
private List<Target> assignWithoutMaintenanceWindow(final DistributionSet distributionSet, final Target savedTarget,
final boolean timeforced) {
return timeforced ? assignDistributionSetTimeForced(distributionSet, savedTarget).getAssignedEntity()
: assignDistributionSet(distributionSet, savedTarget).getAssignedEntity();
}
private List<Target> assignWithMaintenanceWindow(final DistributionSet distributionSet, final Target savedTarget,
final boolean timeforced, final String maintenanceWindowSchedule, final String maintenanceWindowDuration,
final String maintenanceWindowTimeZone) {
return timeforced
? assignDistributionSetWithMaintenanceWindowTimeForced(distributionSet.getId(),
savedTarget.getControllerId(), maintenanceWindowSchedule, maintenanceWindowDuration,
maintenanceWindowTimeZone).getAssignedEntity()
: assignDistributionSetWithMaintenanceWindow(distributionSet.getId(), savedTarget.getControllerId(),
maintenanceWindowSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone)
.getAssignedEntity();
}
protected DistributionSet createDistributionSet() {
DistributionSet distributionSet = testdataFactory.createDistributionSet("");
distributionSet = distributionSetManagement.update(entityFactory.distributionSet()
.update(distributionSet.getId()).description("The descption of the distribution set."));
distributionSet.getModules().forEach(module -> {
final byte[] random = RandomStringUtils.random(5).getBytes();
artifactManagement.create(new ByteArrayInputStream(random), module.getId(), "file1", false, 0);
softwareModuleManagement.update(entityFactory.softwareModule().update(module.getId())
.description("Description of the software module"));
});
return distributionSet;
}
/*
* helper method to give feedback mark an target IN_SNCY *
*/
private void feedbackToByInSync(final DistributionSet savedSet) {
final Action action = deploymentManagement.findActionsByDistributionSet(PAGE, savedSet.getId()).getContent()
.get(0);
controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).status(Status.FINISHED));
}
protected Target createTargetByGivenNameWithAttributes(final String name, final DistributionSet distributionSet) {
return createTargetByGivenNameWithAttributes(name, true, false, distributionSet);
}
protected String getArrayPrefix(final boolean isArray) {
return isArray ? arrayPrefix : "";
}
protected Snippet getResponseFieldTarget(final boolean isArray, final FieldDescriptor... descriptors) {
final String fieldArrayPrefix = getArrayPrefix(isArray);
final List<FieldDescriptor> fields = Lists.newArrayList(
fieldWithPath(fieldArrayPrefix + "createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath(fieldArrayPrefix + "address").description(MgmtApiModelProperties.ADDRESS),
fieldWithPath(fieldArrayPrefix + "createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath(fieldArrayPrefix + "name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath(fieldArrayPrefix + "description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath(fieldArrayPrefix + "controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath(fieldArrayPrefix + "updateStatus").description(MgmtApiModelProperties.UPDATE_STATUS)
.type("enum")
.attributes(key("value").value("['error', 'in_sync', 'pending', 'registered', 'unknown']")),
fieldWithPath(fieldArrayPrefix + "securityToken").description(MgmtApiModelProperties.SECURITY_TOKEN),
fieldWithPath(fieldArrayPrefix + "installedAt").description(MgmtApiModelProperties.INSTALLED_AT),
fieldWithPath(fieldArrayPrefix + "lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
fieldWithPath(fieldArrayPrefix + "lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
fieldWithPath(fieldArrayPrefix + "ipAddress").description(MgmtApiModelProperties.IP_ADDRESS)
.type("String"),
fieldWithPath(fieldArrayPrefix + "lastControllerRequestAt")
.description(MgmtApiModelProperties.LAST_REQUEST_AT).type("Number"),
fieldWithPath(fieldArrayPrefix + "_links.self").ignored());
if (!isArray) {
fields.addAll(Arrays.asList(
fieldWithPath(fieldArrayPrefix + "pollStatus").description(MgmtApiModelProperties.POLL_STATUS),
fieldWithPath(fieldArrayPrefix + "pollStatus.lastRequestAt")
.description(MgmtApiModelProperties.POLL_LAST_REQUEST_AT),
fieldWithPath(fieldArrayPrefix + "pollStatus.nextExpectedRequestAt")
.description(MgmtApiModelProperties.POLL_NEXT_EXPECTED_REQUEST_AT),
fieldWithPath(fieldArrayPrefix + "pollStatus.overdue")
.description(MgmtApiModelProperties.POLL_OVERDUE),
fieldWithPath(fieldArrayPrefix + "_links.assignedDS")
.description(MgmtApiModelProperties.LINKS_ASSIGNED_DS),
fieldWithPath(fieldArrayPrefix + "_links.installedDS")
.description(MgmtApiModelProperties.LINKS_INSTALLED_DS),
fieldWithPath(fieldArrayPrefix + "_links.attributes")
.description(MgmtApiModelProperties.LINKS_ATTRIBUTES),
fieldWithPath(fieldArrayPrefix + "_links.actions")
.description(MgmtApiModelProperties.LINKS_ACTIONS)));
}
fields.addAll(Arrays.asList(descriptors));
return responseFields(fields);
}
protected Snippet getResponseFieldsDistributionSet(final boolean isArray, final FieldDescriptor... descriptors) {
final String arrayPrefix = getArrayPrefix(isArray);
final List<FieldDescriptor> fields = Lists.newArrayList(
fieldWithPath(arrayPrefix + "id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath(arrayPrefix + "name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath(arrayPrefix + "description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath(arrayPrefix + "createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath(arrayPrefix + "createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath(arrayPrefix + "lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath(arrayPrefix + "lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath(arrayPrefix + "type").description(MgmtApiModelProperties.DS_TYPE),
fieldWithPath(arrayPrefix + "requiredMigrationStep")
.description(MgmtApiModelProperties.DS_REQUIRED_STEP),
fieldWithPath(arrayPrefix + "complete").description(MgmtApiModelProperties.DS_COMPLETE),
fieldWithPath(arrayPrefix + "deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath(arrayPrefix + "version").description(MgmtApiModelProperties.VERSION),
fieldWithPath(arrayPrefix + "_links.self").ignored(), fieldWithPath(arrayPrefix + "modules").ignored());
fields.addAll(Arrays.asList(descriptors));
if (!isArray) {
fields.add(fieldWithPath(arrayPrefix + "_links.type").description(MgmtApiModelProperties.DS_TYPE));
fields.add(fieldWithPath(arrayPrefix + "_links.metadata").description(MgmtApiModelProperties.META_DATA));
fields.add(fieldWithPath(arrayPrefix + "_links.modules").description(MgmtApiModelProperties.SM_LIST));
}
return responseFields(fields);
}
protected Snippet getFilterRequestParamter() {
return requestParameters(
parameterWithName("limit").attributes(key("type").value("query"))
.description(ApiModelPropertiesGeneric.LIMIT),
parameterWithName("sort").description(ApiModelPropertiesGeneric.SORT),
parameterWithName("offset").description(ApiModelPropertiesGeneric.OFFSET),
parameterWithName("q").description(ApiModelPropertiesGeneric.FIQL));
}
}

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.documentation;
/**
* Constants for API documentation.
*/
public final class ApiModelPropertiesGeneric {
public static final String ENDING = " of the entity";
// generic
public static final String TENANT = "The tenant";
public static final String ITEM_ID = "The technical identifier " + ENDING;
public static final String NAME = "The name" + ENDING;
public static final String DESCRPTION = "The description" + ENDING;
public static final String COLOUR = "The colour" + ENDING;
public static final String DELETED = "Deleted flag, used for soft deleted entities";
public static final String CREATED_BY = "Entity was originally created by Bosch IoT Permission user (IM: + UUID), Rollout cloud user (CLD: + UUID), AMQP-Controller, anonymous etc.)";
public static final String CREATED_AT = "Entity was originally created at (timestamp UTC in milliseconds)";
public static final String LAST_MODIFIED_BY = "Entity was last modified by Bosch IoT Permission user (IM: + UUID), Rollout cloud user (CLD: + UUID), AMQP-Controller, anonymous etc.)";
public static final String LAST_MODIFIED_AT = "Entity was last modified at (timestamp UTC in milliseconds)";
// Paging elements
public static final String SIZE = "Current page size";
public static final String TOTAL_ELEMENTS = "Total number of elements";
public static final String SELF_LINKS_TO_RESOURCE = "Links to the given resource itself";
private ApiModelPropertiesGeneric() {
// utility class
}
// parameters
public static final String OFFSET = "The paging offset (default is 0).";
public static final String LIMIT = "The maximum number of entries in a page (default is 50).";
public static final String SORT = "The query parameter sort allows to define the sort order for the result of a query. "
+ "A sort criteria consists of the name of a field and the sort direction (ASC for ascending and DESC descending). "
+ "The sequence of the sort criteria (multiple can be used) defines the sort order of the entities in the result.";
public static final String FIQL = "Query fields based on the Feed Item Query Language (FIQL). See link:../developerguide/apispecifications/managementapi/queryparameters.html[FIQL search syntax, window=\"_parent\"].";
// Error/exception handling
public static final String EXCEPTION_CLASS = "The exception class name.";
public static final String ERROR_CODE = "The exception error code.";
public static final String ERROR_MESSAGE = "The exception human readable message.";
public static final String ERROR_PARAMETERS = "The exception message parameters.";
}

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.documentation;
import java.util.List;
import org.springframework.restdocs.payload.FieldDescriptor;
import org.springframework.restdocs.payload.ResponseFieldsSnippet;
/**
* {@link ResponseFieldsSnippet} with public constructor
*/
public class DocumenationResponseFieldsSnippet extends ResponseFieldsSnippet {
public DocumenationResponseFieldsSnippet(final List<FieldDescriptor> descriptors) {
super(descriptors);
}
}

View File

@@ -0,0 +1,209 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.documentation;
/**
* Model properties for the Management API documentation.
*/
public final class MgmtApiModelProperties {
// Versioned entity
public static final String VERSION = "Package version.";
public static final String VENDOR = "The software vendor.";
public static final String ACTION_ID = "ID of the action.";
public static final String LINKS_ASSIGNED_DS = "Links to assigned distribution sets.";
public static final String LINKS_INSTALLED_DS = "Links to installed distribution sets.";
public static final String LINKS_ATTRIBUTES = "Links to attributes of the target.";
public static final String LINKS_ACTIONS = "Links to actions of the target.";
public static final String LINK_TO_ACTION = "The link to the action.";
public static final String LINK_TO_DS = "The link to the distribution set.";
public static final String LINKS_ACTION_STATUSES = "The link to all statuses of the action.";
public static final String LINK_TO_ARTIFACTS = "The link to all artifact of a software module.";
public static final String LINK_TO_SM_TYPE = "The link to the software module type.";
public static final String LINK_TO_METADATA = "The link to the metadata.";
public static final String LINK_TO_MANDATORY_SMT = "Link to mandatory software modules types in this distribution set type.";
public static final String LINK_TO_OPTIONAL_SMT = "Link to optional software modules types in this distribution set type.";
// software module types
public static final String SMT_TYPE = "The type of the software module identified by its key.";
public static final String SMT_VENDOR = "The software vendor of the entity.";
public static final String SMT_VERSION = "The version of the software module type.";
public static final String SMT_KEY = "The key of the software module type.";
public static final String SMT_MAX_ASSIGNMENTS = "Software modules of that type can be assigned at this maximum number (e.g. operating system only once).";
// software module
public static final String SM_TYPE = "The software module type " + ApiModelPropertiesGeneric.ENDING;
public static final String ARTIFACT_HASHES = "Hashes of the artifact.";
public static final String ARTIFACT_SIZE = "Size of the artifact.";
public static final String ARTIFACT_PROVIDED_FILE = "Binary of file.";
public static final String ARTIFACT_PROVIDED_FILENAME = "Filename of the artifact.";
public static final String ARTIFACT_HASHES_SHA1 = "SHA1 hash of the artifact.";
public static final String ARTIFACT_HASHES_MD5 = "MD5 hash of the artifact.";
public static final String ARTIFACT_DOWNLOAD_LINK = "Download link of the artifact.";
public static final String ARTIFACT_LIST = "List of artifacts of given software module.";
// Distribution Set
public static final String DS_OS = "Operating system or firmware software module - DEPRECATED (use modules).";
public static final String DS_RUNTIME = "Runtime software module (e.g. JVM) - DEPRECATED (use modules).";
public static final String DS_APPLICATION = "Application software module (e.g. OSGi container) - DEPRECATED (use modules).";
public static final String DS_MODULES = "Software modules (e.g. OSGi bundles, runtimes).";
public static final String DS_REQUIRED_STEP = "True if DS a required migration step. As a result the DS will be installed even when a newer. (note: updatable only if DS is not yet assigned to a target)";
public static final String DS_ASSIGNED_TARGETS = "Targets that have this distribution set assigned.";
public static final String DS_INSTALLED_TARGETS = "Targets that have this distribution set installed.";
public static final String DS_LIST = "List of distribution sets.";
public static final String DS_NEW_ASSIGNED_TARGETS = "Targets that now have this distribution set assigned.";
public static final String DS_ALREADY_ASSIGNED_TARGETS = "Targets that had this distribution set already assigned (in \"offline\" case this includes targets that have arbitrary updates running)";
public static final String DS_TOTAL_ASSIGNED_TARGETS = "Overall assigned as part of this request.";
public static final String DS_ID = "Id of the distribution set.";
// Target
public static final String INSTALLED_AT = "Installation time of current installed DistributionSet.";
public static final String LAST_REQUEST_AT = "Last time where the target polled the server, same as pollStatus.lastRequestAt.";
// poll status
public static final String POLL_LAST_REQUEST_AT = "Last time when the target polled the server.";
public static final String POLL_NEXT_EXPECTED_REQUEST_AT = "Next expected time when the target polls the server.";
public static final String POLL_STATUS = "Poll status of the target. In many scenarios that target will poll the update server on a regular basis to look for potential updates. If that poll does not happen it might imply that the target is offline.";
public static final String POLL_OVERDUE = "Defines if the target poll time is overdue based on the next expected poll time plus the configured overdue poll time threshold.";
// rollout
public static final String ROLLOUT_FILTER_QUERY = "target filter query language expression";
public static final String ROLLOUT_GROUP_FILTER_QUERY = "target filter query language expression that selects a subset of targets which match the target filter of the Rollout";
public static final String ROLLOUT_GROUP_TARGET_PERCENTAGE = "percentage of remaining and matching targets that should be added to this group";
public static final String ROLLOUT_DS_ID = "the ID of distributionset of this rollout";
public static final String ROLLOUT_TOTAL_TARGETS = "the total targets of a rollout";
public static final String ROLLOUT_TOTAL_TARGETS_PER_STATUS = "the total targets per status";
public static final String ROLLOUT_STATUS = "the status of this rollout";
public static final String ROLLOUT_GROUP_STATUS = "the status of this rollout group";
public static final String ROLLOUT_AMOUNT_GROUPS = "the amount of groups the rollout should split targets into";
public static final String ROLLOUT_GROUPS = "the list of group definitions";
public static final String ROLLOUT_SUCCESS_CONDITION = "the success condition which takes in place to evaluate if a rollout group is successful and so the next group can be started";
public static final String ROLLOUT_SUCCESS_CONDITION_CONDITION = "the type of the condition";
public static final String ROLLOUT_SUCCESS_CONDITION_EXP = "the expression according to the condition, e.g. the value of threshold in percentage";
public static final String ROLLOUT_SUCCESS_ACTION = "the success action which takes in place to execute in case the success action is fulfilled";
public static final String ROLLOUT_SUCCESS_ACTION_ACTION = "the success action to execute";
public static final String ROLLOUT_SUCCESS_ACTION_EXP = "the expression for the success action";
public static final String ROLLOUT_ERROR_CONDITION = "the error condition which takes in place to evaluate if a rollout group encounter errors";
public static final String ROLLOUT_ERROR_CONDITION_CONDITION = "the type of the condition";
public static final String ROLLOUT_ERROR_CONDITION_EXP = "the expression according to the condition, e.g. the value of threshold in percentage";
public static final String ROLLOUT_ERROR_ACTION = "the error action which is executed if the error condition is fulfilled";
public static final String ROLLOUT_ERROR_ACTION_ACTION = "the error action to execute";
public static final String ROLLOUT_ERROR_ACTION_EXP = "the expression for the error action";
public static final String ROLLOUT_LINKS_START_SYNC = "Link to start the rollout in sync mode";
public static final String ROLLOUT_LINKS_START_ASYNC = "Link to start the rollout in async mode";
public static final String ROLLOUT_LINKS_PAUSE = "Link to pause a running rollout";
public static final String ROLLOUT_LINKS_RESUME = "Link to resume a paused rollout";
public static final String ROLLOUT_LINKS_GROUPS = "Link to retrieve the groups a rollout";
public static final String ROLLOUT_START_ASYNC = "Start the rollout asynchronous";
public static final String UPDATE_STATUS = "Current update status of the target.";
public static final String TARGET_ATTRIBUTES = "Target attributes.";
public static final String TARGET_LIST = "List of provisioning targets.";
public static final String SM_LIST = "List of software modules.";
public static final String ROLLOUT_LIST = "list of rollouts";
public static final String ACTION_TYPE = "Type of action.";
public static final String ACTION_FORCE_TYPE = "Force type of the action that provides a hint if the controller should apply the action immediately or whenever possible.";
public static final String ACTION_FORCE_TIME = "In case of timeforced mode the difference, measured in milliseconds, between the time the action should switch to forced and midnight, January 1, 1970 UTC.";
public static final String ACTION_FORCED = "Set to forced in order to switch action to forced mode.";
public static final String ACTION_STATUS_TYPE = "Type of the action status.";
public static final String ACTION_STATUS_MESSAGES = "Messages related to the status.";
public static final String ACTION_STATUS_REPORTED_AT = "Time at which the status was reported (server time).";
public static final String ACTION_STATUS_LIST = "List of action status.";
public static final String ACTION_EXECUTION_STATUS = "Status of action.";
public static final String ACTION_LIST = "List of actions.";
public static final String IP_ADDRESS = "Last known IP address of the target. Only presented if IP address of the target itself is known (connected directy through DDI API).";
public static final String ADDRESS = "The last known address URI of the target. Includes information of the target is connected either directly (DDI) through HTTP or indirectly (DMF) through amqp.";
public static final String SECURITY_TOKEN = "Pre-Shared key that allows targets to authenticate at Direct Device Integration API if enabled in the tenant settings.";
public static final String META_DATA = "List of metadata.";
public static final String META_DATA_KEY = "Metadata property key.";
public static final String META_DATA_VALUE = "Metadata property value.";
public static final String SM_META_DATA_TARGET_VISIBLE = "Metadata property is visible to targets as part of software update action.";
public static final String SM_TYPE_KEY = "Key that can be interpreted by the target.";
public static final String SM_MAX_ASSIGNMENTS = "Maximum number of assigments to a distribution set/target, e.g. only one firmware but multiple applications.";
public static final String SM_TYPE_LIST = "List of software modules types.";
public static final String DS_TYPE_KEY = "Functional key of the distribution set type.";
public static final String DS_TYPE_LIST = "List of distribution set types.";
public static final String DS_TYPE = "The type of the distribution set.";
public static final String DS_COMPLETE = "True of the distribution set software module setup is complete as defined by the distribution set type.";
public static final String DS_TYPE_MANDATORY_MODULES = "Mandatory module type IDs.";
public static final String DS_TYPE_OPTIONAL_MODULES = "Optional module type IDs.";
public static final String MAINTENANCE_WINDOW = "Separation of download and install by defining a maintenance window for the installation.";
public static final String MAINTENANCE_WINDOW_SCHEDULE = "Schedule for the maintenance window start in quartz cron notation, such as '0 15 10 * * ? 2018' for 10:15am every day during the year 2018.";
public static final String MAINTENANCE_WINDOW_DURATION = "Duration of the window, such as '02:00:00' for 2 hours.";
public static final String MAINTENANCE_WINDOW_TIMEZONE = "A time-zone offset from Greenwich/UTC, such as '+02:00'.";
public static final String MAINTENANCE_WINDOW_NEXT_START_AT = "The time (timestamp UTC in milliseconds) of the next maintenance window start";
// target filter query
public static final String TARGET_FILTER_QUERY = "target filter query expression";
public static final String TARGET_FILTER_QUERIES_LIST = "List of target filter queries.";
public static final String TARGET_FILTER_QUERY_AUTO_ASSIGN_DS_ID = "Auto assign distribution set id";
public static final String TARGET_FILTER_QUERY_LINK_AUTO_ASSIGN_DS = "Link to manage the auto assign distribution set";
public static final String TARGET_FILTER_QUERY_PARAM_Q = "Name filter";
// request parameter
public static final String FORCETIME = "Forcetime in milliseconds.";
public static final String FORCE = "Force as boolean.";
public static final String FORCETIME_TYPE = "The type of the forcetime.";
public static final String TARGET_ASSIGNED = "The number of targets that have been assigned as part of this operation.";
public static final String TARGET_ASSIGNED_ALREADY = "The number of targets which already had been the assignment.";
public static final String TARGET_ASSIGNED_TOTAL = "The total number of targets that are part of this operation.";
public static final String ASSIGNED_TARGETS = "Assigned targets.";
public static final String UN_ASSIGNED_TARGETS = "Unassigned targets.";
public static final String LINKS_ASSIGNED_TARGETS = "Links to assigned targets.";
public static final String ASSIGNED_DISTRIBUTION_SETS = "Assigned distribution sets.";
public static final String UN_ASSIGNED_DISTRIBUTION_SETS = "Unassigned distribution sets.";
public static final String LINKS_ASSIGNED_DISTRIBUTION_SETS = "Links to assigned distribution sets.";
public static final Object OFFLINE_UPDATE = "Offline update (set param to true) that is only reported but not managed by the service, "
+ "e.g. defaults set in factory, manual updates or migrations from other update systems. A completed action is added to the history of the target(s)."
+ " Target is set to IN_SYNC state as both assigend and installed DS are set. "
+ "Note: only executed if the target has currently no running update.";
// configuration
public static final String CONFIG_LIST = "List of all available configuration parameter.";
public static final String CONFIG_VALUE = "Current value of of configuration parameter.";
public static final String CONFIG_GLOBAL = "true - if the current value is the global configuration value, false - if there is a tenant specific value configured.";
public static final String CONFIG_PARAM = "The name of the configuration parameter.";
}

View File

@@ -0,0 +1,305 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.mgmt.documentation;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedDistributionSetRequestBody;
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.documentation.DocumenationResponseFieldsSnippet;
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.FieldDescriptor;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.restdocs.snippet.Snippet;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Documentation generation for Management API for {@link DistributionSetTag}.
*
*/
@Features("Spring Rest Docs Tests - DistributionSetTag")
@Stories("DistributionSet Tag Resource")
public class DistributionSetTagResourceDocumentationTest extends AbstractApiRestDocumentation {
private DistributionSet distributionSet;
@Override
@Before
public void setUp() {
resourceName = "distributionsettag";
super.setUp();
distributionSet = createDistributionSet();
}
@Test
@Description("Handles the GET request of retrieving all distribution set tags")
public void getDistributionSetTags() throws Exception {
createDistributionSetTag();
arrayPrefix = "content[].";
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING)).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(getResponseFieldsTag(true,
fieldWithPath("size").type(JsonFieldType.NUMBER).description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_LIST))));
}
@Test
@Description("Handles the GET request of retrieving all distribution set tags based by parameter")
public void getDistributionSetTagsWithParameters() throws Exception {
createDistributionSetTag();
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
+ "?limit=10&sort=name:ASC&offset=0&q=name==DsTag")).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print()).andDo(this.document.document(getFilterRequestParamter()));
}
@Test
@Description("Handles the GET request of retrieving a single distribution set tag")
public void getDistributionSetTag() throws Exception {
final Long tagId = createDistributionSetTagId();
mockMvc.perform(
get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/{distributionsetTagId}", tagId))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(pathParameters(
parameterWithName("distributionsetTagId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getResponseFieldsTag(false)));
}
@Test
@Description("Handles the POST request of creating new distribution set tag. The request body must always be a list of tags.")
public void createDistributionSetTags() throws Exception {
final MgmtTagRequestBodyPut bodyPut = createDSBody();
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(Arrays.asList(bodyPut));
this.mockMvc
.perform(post(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING).content(json)
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isCreated()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(getRequestFieldsTag(true), getResponseFieldsTag(true)));
}
@Test
@Description("Handles the PUT request of updating a single distribution set tag.")
public void updateDistributionSetTag() throws Exception {
final Long tagId = createDistributionSetTagId();
final MgmtTagRequestBodyPut bodyPut = createDSBody();
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(bodyPut);
this.mockMvc
.perform(
put(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/{distributionsetTagId}", tagId)
.content(json).contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("distributionsetTagId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
getRequestFieldsTag(false), getResponseFieldsTag(false)));
}
private MgmtTagRequestBodyPut createDSBody() {
final MgmtTagRequestBodyPut bodyPut = new MgmtTagRequestBodyPut();
bodyPut.setColour("red");
bodyPut.setDescription("ds tag description");
bodyPut.setName("ds tag");
return bodyPut;
}
@Test
@Description("Handles the DELETE request for a single distribution set tag")
public void deleteDistributionSetTag() throws Exception {
final Long tagId = createDistributionSetTagId();
this.mockMvc
.perform(delete(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/{distributionsetTagId}",
tagId).contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(pathParameters(
parameterWithName("distributionsetTagId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving all assigned distribution sets by the given tag id.")
public void getAssignedDistributionSets() throws Exception {
final DistributionSetTag tag = createDistributionSetTag();
distributionSetManagement.assignTag(Arrays.asList(distributionSet.getId()), tag.getId());
arrayPrefix = "content[].";
this.mockMvc
.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
+ MgmtRestConstants.DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING, tag.getId())
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("distributionsetTagId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
getResponseFieldsDistributionSet(true,
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_LIST))));
}
@Test
@Description("andles the POST request to toggle the assignment of distribution sets by the given tag id.")
public void toggleTagAssignment() throws Exception {
final DistributionSet unassignDS = testdataFactory.createDistributionSet("unassign");
final Long tagId = createDistributionSetTagId();
final MgmtAssignedDistributionSetRequestBody body = new MgmtAssignedDistributionSetRequestBody();
body.setDistributionSetId(distributionSet.getId());
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(Arrays.asList(body));
this.mockMvc
.perform(post(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
+ MgmtRestConstants.DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING
+ "/toggleTagAssignment", tagId).content(json).contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("distributionsetTagId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
getRequestFieldsDistributionSetAssignment(true),
getResponseAssignmentResult(distributionSet, unassignDS)
));
}
@Test
@Description("Handles the POST request to assign distribution sets to the given tag id.")
public void assignDistributionSets() throws Exception {
final Long tagId = createDistributionSetTagId();
final MgmtAssignedDistributionSetRequestBody body = new MgmtAssignedDistributionSetRequestBody();
body.setDistributionSetId(distributionSet.getId());
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(Arrays.asList(body));
this.mockMvc
.perform(post(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
+ MgmtRestConstants.DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING, tagId).content(json)
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("distributionsetTagId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
getRequestFieldsDistributionSetAssignment(true), getResponseFieldsDistributionSet(true)));
}
@Test
@Description("Handles the DELETE request to unassign one distribution set from the given tag id.")
public void unassignDistributionSet() throws Exception {
final Long tagId = createDistributionSetTagId();
this.mockMvc
.perform(delete(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
+ MgmtRestConstants.DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING
+ "/{distributionsetId}", tagId, distributionSet.getId())
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(pathParameters(
parameterWithName("distributionsetTagId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("distributionsetId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
private Snippet getRequestFieldsTag(final boolean isArray) {
final String arrayPrefix = getArrayPrefix(isArray);
return requestFields(requestFieldWithPath(arrayPrefix + "name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPath(arrayPrefix + "description").description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath(arrayPrefix + "colour").description(ApiModelPropertiesGeneric.COLOUR));
}
private Snippet getRequestFieldsDistributionSetAssignment(final boolean isArray) {
final String arrayPrefix = getArrayPrefix(isArray);
return requestFields(requestFieldWithPath(arrayPrefix + "id").description(ApiModelPropertiesGeneric.ITEM_ID));
}
private Snippet getResponseFieldsTag(final boolean isArray, final FieldDescriptor... descriptors)
throws JsonProcessingException {
final String arrayPrefix = getArrayPrefix(isArray);
final List<FieldDescriptor> allFieldDescriptor = new ArrayList<>();
allFieldDescriptor.addAll(Arrays.asList(descriptors));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "id").description(ApiModelPropertiesGeneric.ITEM_ID));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "name").description(ApiModelPropertiesGeneric.NAME));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "description").description(ApiModelPropertiesGeneric.DESCRPTION));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "createdBy").description(ApiModelPropertiesGeneric.CREATED_BY));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "createdAt").description(ApiModelPropertiesGeneric.CREATED_AT));
allFieldDescriptor.add(
fieldWithPath(arrayPrefix + "lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY));
allFieldDescriptor.add(
fieldWithPath(arrayPrefix + "lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "colour").description(ApiModelPropertiesGeneric.COLOUR));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.self").ignored());
if (!isArray) {
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.assignedDistributionSets")
.description(MgmtApiModelProperties.LINKS_ASSIGNED_DISTRIBUTION_SETS));
}
return new DocumenationResponseFieldsSnippet(allFieldDescriptor);
}
private Snippet getResponseFieldsTag(final boolean isArray) throws JsonProcessingException {
return getResponseFieldsTag(isArray, new FieldDescriptor[0]);
}
private Snippet getResponseAssignmentResult(final DistributionSet assignment, final DistributionSet unassignment)
throws JsonProcessingException {
return responseFields(
fieldWithPath("assignedDistributionSets").description(MgmtApiModelProperties.ASSIGNED_DISTRIBUTION_SETS)
.type("Array[Object]"),
fieldWithPath("unassignedDistributionSets")
.description(MgmtApiModelProperties.UN_ASSIGNED_DISTRIBUTION_SETS).type("Array[Object]"));
}
private DistributionSetTag createDistributionSetTag() {
final DistributionSetTag updateTag = distributionSetTagManagement
.create(entityFactory.tag().create().name("DsTag"));
return distributionSetTagManagement.update(entityFactory.tag().update(updateTag.getId())
.description("My name is " + updateTag.getName()).colour("default"));
}
private Long createDistributionSetTagId() {
return createDistributionSetTag().getId();
}
}

View File

@@ -0,0 +1,434 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.mgmt.documentation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.restdocs.snippet.Attributes.key;
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.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Documentation generation for Management API for {@link DistributionSetType}.
*
*/
@Features("Spring Rest Docs Tests - DistributionSetType")
@Stories("DistributionSetTypes Resource")
public class DistributionSetTypesDocumentationTest extends AbstractApiRestDocumentation {
@Override
@Before
public void setUp() {
this.resourceName = "distributionsettypes";
super.setUp();
}
@Test
@Description("Handles the GET request of retrieving all distribution set types within SP. Required Permission: READ_REPOSITORY.")
public void getDistributionSetTypes() throws Exception {
distributionSetTypeManagement.update(entityFactory.distributionSetType()
.update(testdataFactory.createDistributionSet().getType().getId()).description("Desc1234"));
mockMvc.perform(
get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.total", equalTo(4)))
.andDo(this.document.document(responseFields(
fieldWithPath("size").type(JsonFieldType.NUMBER).description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_LIST),
fieldWithPath("content[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("content[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("content[].description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("content[].key").description(MgmtApiModelProperties.DS_TYPE_KEY),
fieldWithPath("content[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("content[].lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
fieldWithPath("content[].lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
fieldWithPath("content[].name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("content[]._links.self").ignored())));
}
@Test
@Description("Handles the GET request of retrieving all distribution set types within SP with a defined page size and offset, sortet by name in descending order and filtered down to all targets which name starts with 'a'. Required Permission: READ_REPOSITORY.")
public void getDistributionSetTypesWithParameters() throws Exception {
distributionSetTypeManagement.update(entityFactory.distributionSetType()
.update(testdataFactory.createDistributionSet().getType().getId()).description("Desc1234"));
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON)
.param("offset", "1").param("limit", "2").param("sort", "name:DESC").param("q", "name==a*"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(getFilterRequestParamter()));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Handles the POST request for creating new distribution set types within SP. The request body "
+ "must always be a list of types. Required Permission: CREATE_REPOSITORY.")
public void postDistributionSetTypes() throws Exception {
assertThat(distributionSetTypeManagement.count()).isEqualTo(4);
final List<DistributionSetType> types = new ArrayList<>();
types.add(entityFactory.distributionSetType().create().key("test1").name("TestName1").description("Desc1")
.mandatory(osType).optional(runtimeType).build());
mockMvc.perform(post(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING)
.content(JsonBuilder.distributionSetTypesCreateValidFieldsOnly(types))
.contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated()).andDo(
this.document.document(
requestFields(
requestFieldWithPath("[]key").description(MgmtApiModelProperties.DS_TYPE_KEY),
requestFieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME),
optionalRequestFieldWithPath("[]description")
.description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("[]mandatorymodules")
.description(MgmtApiModelProperties.DS_TYPE_MANDATORY_MODULES),
optionalRequestFieldWithPath("[]optionalmodules")
.description(MgmtApiModelProperties.DS_TYPE_OPTIONAL_MODULES)),
responseFields(
fieldWithPath("[]createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("[]createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("[].description")
.description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("[]key").description(MgmtApiModelProperties.DS_TYPE_KEY),
fieldWithPath("[]id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("[]lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
fieldWithPath("[]lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
fieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("[]deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("[]_links.self").ignored())));
}
@Test
@Description("Handles the GET request of retrieving a single distribution set type within SP. Required Permission: READ_REPOSITORY")
public void deleteDistributionSetType() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.update(entityFactory.distributionSetType()
.update(testdataFactory.createDistributionSet().getType().getId()).description("Desc1234"));
mockMvc.perform(delete(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING + "/{distributionSetTypeId}",
testType.getId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(pathParameters(
parameterWithName("distributionSetTypeId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the DELETE request for a single distribution set type within SP. Required Permission: DELETE_REPOSITORY.")
public void getDistributionSetType() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.update(entityFactory.distributionSetType()
.update(testdataFactory.createDistributionSet().getType().getId()).description("Desc1234"));
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING + "/{distributionSetTypeId}",
testType.getId()).accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("distributionSetTypeId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("key").description(MgmtApiModelProperties.DS_TYPE_KEY),
fieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
.type("Number"),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
.type("String"),
fieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("_links.self").ignored(),
fieldWithPath("_links.mandatorymodules")
.description(MgmtApiModelProperties.LINK_TO_MANDATORY_SMT),
fieldWithPath("_links.optionalmodules")
.description(MgmtApiModelProperties.LINK_TO_OPTIONAL_SMT))));
}
@Test
@Description("Handles the GET request of retrieving all distribution set types within SP based on parameter. Required Permission: READ_REPOSITORY.")
public void getDistributionSetTypesWithParameter() throws Exception {
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING
+ "?limit=10&sort=name:ASC&offset=0&q=name==a")).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(requestParameters(
parameterWithName("limit").attributes(key("type").value("query"))
.description(ApiModelPropertiesGeneric.LIMIT),
parameterWithName("sort").description(ApiModelPropertiesGeneric.SORT),
parameterWithName("offset").description(ApiModelPropertiesGeneric.OFFSET),
parameterWithName("q").description(ApiModelPropertiesGeneric.FIQL))));
}
@Test
@Description("Handles the PUT request for a single distribution set type within SP. Required Permission: UPDATE_REPOSITORY.")
public void putDistributionSetType() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.update(entityFactory.distributionSetType()
.update(testdataFactory.createDistributionSet().getType().getId()).description("Desc1234"));
final String body = new JSONObject().put("description", "an updated desription").toString();
this.mockMvc
.perform(put(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING + "/{distributionSetTypeId}",
testType.getId()).content(body).contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("distributionSetTypeId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(
requestFieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION)),
responseFields(fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("key").description(MgmtApiModelProperties.DS_TYPE_KEY),
fieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
.type("Number"),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
.type("String"),
fieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("_links.self").ignored(),
fieldWithPath("_links.mandatorymodules")
.description(MgmtApiModelProperties.LINK_TO_MANDATORY_SMT),
fieldWithPath("_links.optionalmodules")
.description(MgmtApiModelProperties.LINK_TO_OPTIONAL_SMT))));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Handles the GET request of retrieving the list of mandatory software module types in that distribution set type. Required Permission: READ_REPOSITORY.")
public void getMandatoryModules() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key("test1").name("TestName1").description("Desc1").mandatory(osType).optional(runtimeType));
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING
+ "/{distributionSetTypeId}/mandatorymoduletypes", testType.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(
pathParameters(parameterWithName("distributionSetTypeId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("[]createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("[]createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("[]description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("[]key").description(MgmtApiModelProperties.SM_TYPE_KEY),
fieldWithPath("[]maxAssignments")
.description(MgmtApiModelProperties.SMT_MAX_ASSIGNMENTS),
fieldWithPath("[]id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("[]lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
fieldWithPath("[]lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
fieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("[]deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("[]_links.self").ignored())));
}
@Test
@Description("Handles the POST request for adding a mandatory software module type to a distribution set type."
+ "Note that a DS type cannot be changed after it has been used by a DS. Required Permission: "
+ SpPermission.UPDATE_REPOSITORY + " and " + SpPermission.READ_REPOSITORY)
public void postMandatoryModule() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.create(
entityFactory.distributionSetType().create().key("test1").name("TestName1").description("Desc1"));
mockMvc.perform(post(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING
+ "/{distributionSetTypeId}/mandatorymoduletypes", testType.getId())
.content("{\"id\":" + osType.getId() + "}").contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("distributionSetTypeId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(requestFieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving the list of software module types in that distribution set. "
+ "Note that a DS type cannot be changed after it has been used by a DS. Required permissions: "
+ SpPermission.UPDATE_REPOSITORY + " and " + SpPermission.READ_REPOSITORY)
public void deleteMandatoryModule() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key("test1").name("TestName1").description("Desc1").mandatory(osType).optional(runtimeType));
mockMvc.perform(delete(
MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING
+ "/{distributionSetTypeId}/mandatorymoduletypes/{softwareModuleTypeId}",
testType.getId(), osType.getId()).contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(pathParameters(
parameterWithName("distributionSetTypeId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("softwareModuleTypeId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving the single mandatory software module type in that distribution set type. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getMandatoryModule() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key("test1").name("TestName1").description("Desc1").mandatory(osType).optional(runtimeType));
mockMvc.perform(get(
MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING
+ "/{distributionSetTypeId}/mandatorymoduletypes/{softwareModuleTypeId}",
testType.getId(), osType.getId()).contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(pathParameters(
parameterWithName("distributionSetTypeId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("softwareModuleTypeId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("key").description(MgmtApiModelProperties.SM_TYPE_KEY),
fieldWithPath("maxAssignments").description(MgmtApiModelProperties.SMT_MAX_ASSIGNMENTS),
fieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
.type("Number"),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
.type("String"),
fieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("_links.self").ignored())));
}
@Test
@Description("Handles the GET request of retrieving the list of optional software module types in that distribution set type. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getOptionalModules() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key("test1").name("TestName1").description("Desc1").mandatory(osType).optional(runtimeType));
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING
+ "/{distributionSetTypeId}/optionalmoduletypes", testType.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(
pathParameters(parameterWithName("distributionSetTypeId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("[]createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("[]createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("[]description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("[]key").description(MgmtApiModelProperties.SM_TYPE_KEY),
fieldWithPath("[]maxAssignments")
.description(MgmtApiModelProperties.SMT_MAX_ASSIGNMENTS),
fieldWithPath("[]id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("[]lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath("[]lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("[]deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("[]_links.self").ignored())));
}
@Test
@Description("Handles the POST request for adding an optional software module type to a distribution set type."
+ "Note that a DS type cannot be changed after it has been used by a DS. Required Permission: "
+ SpPermission.UPDATE_REPOSITORY + " and " + SpPermission.READ_REPOSITORY)
public void postOptionalModule() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.create(
entityFactory.distributionSetType().create().key("test1").name("TestName1").description("Desc1"));
mockMvc.perform(post(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING
+ "/{distributionSetTypeId}/optionalmoduletypes", testType.getId())
.content("{\"id\":" + appType.getId() + "}").contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("distributionSetTypeId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(requestFieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles DELETE request for removing an optional module from the distribution set type."
+ "Note that a DS type cannot be changed after it has been used by a DS. Required Permission: "
+ SpPermission.UPDATE_REPOSITORY + " and " + SpPermission.READ_REPOSITORY)
public void deleteOptionalModule() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key("test1").name("TestName1").description("Desc1").mandatory(osType).optional(runtimeType));
mockMvc.perform(delete(
MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING
+ "/{distributionSetTypeId}/optionalmoduletypes/{softwareModuleTypeId}",
testType.getId(), appType.getId()).contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(pathParameters(
parameterWithName("distributionSetTypeId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("softwareModuleTypeId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving the single optional software module type in that distribution set type. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getOptionalModule() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key("test1").name("TestName1").description("Desc1").mandatory(osType).optional(appType));
mockMvc.perform(get(
MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING
+ "/{distributionSetTypeId}/optionalmoduletypes/{softwareModuleTypeId}",
testType.getId(), appType.getId()).contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(pathParameters(
parameterWithName("distributionSetTypeId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("softwareModuleTypeId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("key").description(MgmtApiModelProperties.SM_TYPE_KEY),
fieldWithPath("maxAssignments").description(MgmtApiModelProperties.SMT_MAX_ASSIGNMENTS),
fieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
.type("Number"),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
.type("String"),
fieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("_links.self").ignored())));
}
}

View File

@@ -0,0 +1,659 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.mgmt.documentation;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.restdocs.snippet.Attributes.key;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.Arrays;
import java.util.List;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import com.google.common.collect.Lists;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Documentation generation for Management API for {@link DistributionSet}.
*
*/
@Features("Spring Rest Docs Tests - DistributionSet")
@Stories("DistributionSet Resource")
public class DistributionSetsDocumentationTest extends AbstractApiRestDocumentation {
@Override
@Before
public void setUp() {
resourceName = "distributionsets";
super.setUp();
}
@Test
@Description("Get Distribution Set. Handles the GET request of retrieving a single distribution set within SP. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getDistributionSet() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}", set.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(
pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getResponseFieldsDistributionSet(false)));
}
@Test
@Description("Get paged list of Distribution Sets. Required Permission: " + SpPermission.READ_REPOSITORY)
public void getDistributionSets() throws Exception {
testdataFactory.createUpdatedDistributionSet();
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(responseFields(
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER).description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.DS_LIST),
fieldWithPath("content[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("content[].name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("content[].description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("content[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("content[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("content[].lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath("content[].lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath("content[].type").description(MgmtApiModelProperties.DS_TYPE),
fieldWithPath("content[].requiredMigrationStep")
.description(MgmtApiModelProperties.DS_REQUIRED_STEP),
fieldWithPath("content[].complete").description(MgmtApiModelProperties.DS_COMPLETE),
fieldWithPath("content[].deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("content[].version").description(MgmtApiModelProperties.VERSION),
fieldWithPath("content[]._links.self").ignored())));
}
@Test
@Description("Get paged list of Distribution Sets with given page size and offset including sorting by name descending and filter down to all sets which name starts with 'testDs'. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getDistributionSetsWithParameters() throws Exception {
final List<DistributionSet> sets = testdataFactory.createDistributionSets("testDS", 3);
sets.forEach(set -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).description("updated description")));
mockMvc.perform(
get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).param("offset", "1").param("limit", "2")
.param("sort", "version:DESC").param("q", "name==testDS*").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(getFilterRequestParamter()));
}
@Test
@Description("Handles the DELETE request for a single Distribution Set within SP. Required Permission: "
+ SpPermission.DELETE_REPOSITORY)
public void deleteDistributionSet() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
this.mockMvc
.perform(delete(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}",
set.getId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Create Distribution Sets. Handles the POST request of creating new distribution sets within SP. The request body must always be a list of sets. Required Permission: "
+ SpPermission.CREATE_REPOSITORY)
public void createDistributionSets() throws Exception {
final SoftwareModule ah = testdataFactory.createSoftwareModuleApp();
final SoftwareModule os = testdataFactory.createSoftwareModuleOs();
final DistributionSet one = testdataFactory.generateDistributionSet("one", "one", standardDsType,
Arrays.asList(os, ah));
final DistributionSet two = testdataFactory.generateDistributionSet("two", "two", standardDsType,
Arrays.asList(os, ah));
final DistributionSet three = testdataFactory.generateDistributionSet("three", "three", standardDsType,
Arrays.asList(os, ah), true);
final List<DistributionSet> sets = Arrays.asList(one, two, three);
this.mockMvc
.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/")
.content(JsonBuilder.distributionSetsCreateValidFieldsOnly(sets))
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isCreated()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
requestFields(requestFieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPath("[]description").description(ApiModelPropertiesGeneric.DESCRPTION),
requestFieldWithPath("[]version").description(MgmtApiModelProperties.VERSION),
optionalRequestFieldWithPath("[]requiredMigrationStep")
.description(MgmtApiModelProperties.DS_REQUIRED_STEP),
requestFieldWithPath("[]type").description(MgmtApiModelProperties.DS_TYPE),
optionalRequestFieldWithPath("[]modules").ignored()),
getResponseFieldsDistributionSet(true)));
}
@Test
@Description("Handles the UPDATE request for a single Distribution Set within SP. Required Permission: "
+ SpPermission.UPDATE_REPOSITORY)
public void updateDistributionSet() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
final DistributionSet update = entityFactory.distributionSet().create().name("another Name")
.version("another Version").description("a new description").requiredMigrationStep(true).build();
mockMvc.perform(put(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}", set.getId())
.content(JsonBuilder.distributionSetUpdateValidFieldsOnly(update))
.contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(
pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(optionalRequestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
optionalRequestFieldWithPath("version").description(MgmtApiModelProperties.VERSION),
optionalRequestFieldWithPath("description")
.description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("requiredMigrationStep")
.description(MgmtApiModelProperties.DS_REQUIRED_STEP)),
getResponseFieldsDistributionSet(false)));
}
@Test
@Description("Handles the GET request for retrieving assigned targets of a single distribution set. Required Permission: "
+ SpPermission.READ_REPOSITORY + " and " + SpPermission.READ_TARGET)
public void getAssignedTargets() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
final Target target = testdataFactory.createTarget();
// assign knownTargetId to distribution set
assignDistributionSet(set.getId(), target.getControllerId());
mockMvc.perform(
get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/assignedTargets",
set.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(
pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_LIST)
.type("Array[Object]"))));
}
@Test
@Description("Handles the GET request for retrieving assigned target filter queries of a single distribution set. Required Permission: "
+ SpPermission.READ_REPOSITORY + " and " + SpPermission.READ_TARGET)
public void getAutoAssignTargetFilterQueries() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name("filter1").query("name==a").set(set));
targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name("filter2").query("name==b").set(set));
mockMvc.perform(get(
MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/autoAssignTargetFilters",
set.getId()).accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(
pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_FILTER_QUERIES_LIST)
.type("Array[Object]"))));
}
@Test
@Description("Handles the GET request for retrieving assigned target filter queries of a single distribution set with a defined page size and offset, sorted by name in descending order and filtered down to all targets with a name that ends with '1'. Required Permission: "
+ SpPermission.READ_REPOSITORY + " and " + SpPermission.READ_TARGET)
public void getAutoAssignTargetFilterQueriesWithParameters() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name("filter1").query("name==a").set(set));
mockMvc.perform(get(
MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + set.getId() + "/autoAssignTargetFilters")
.param("offset", "1").param("limit", "2").param("sort", "name:DESC").param("q", "name==*1")
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(requestParameters(
parameterWithName("limit").attributes(key("type").value("query"))
.description(ApiModelPropertiesGeneric.LIMIT),
parameterWithName("sort").description(ApiModelPropertiesGeneric.SORT),
parameterWithName("offset").description(ApiModelPropertiesGeneric.OFFSET),
parameterWithName("q").description(ApiModelPropertiesGeneric.FIQL))));
}
@Test
@Description("Handles the GET request for retrieving assigned targets of a single distribution set with a defined page size and offset, sorted by name in descending order and filtered down to all targets which controllerID starts with 'target'. Required Permission: "
+ SpPermission.READ_REPOSITORY + " and " + SpPermission.READ_TARGET)
public void getAssignedTargetsWithParameters() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
assignDistributionSet(set, testdataFactory.createTargets(5, "targetMisc", "Test targets for query"))
.getAssignedEntity();
mockMvc.perform(
get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + set.getId() + "/assignedTargets")
.param("offset", "1").param("limit", "2").param("sort", "name:DESC")
.param("q", "controllerId==target*").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(requestParameters(
parameterWithName("limit").attributes(key("type").value("query"))
.description(ApiModelPropertiesGeneric.LIMIT),
parameterWithName("sort").description(ApiModelPropertiesGeneric.SORT),
parameterWithName("offset").description(ApiModelPropertiesGeneric.OFFSET),
parameterWithName("q").description(ApiModelPropertiesGeneric.FIQL))));
}
@Test
@Description("Handles the GET request for retrieving installed targets of a single distribution set with a defined page size and offset, sortet by name in descending order and filtered down to all targets which controllerID starts with 'target'. Required Permission: "
+ SpPermission.READ_REPOSITORY + " and " + SpPermission.READ_TARGET)
public void getInstalledTargetsWithParameters() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
final List<Target> targets = assignDistributionSet(set,
testdataFactory.createTargets(5, "targetMisc", "Test targets for query")).getAssignedEntity();
testdataFactory.sendUpdateActionStatusToTargets(targets, Status.FINISHED, "some message");
mockMvc.perform(
get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + set.getId() + "/installedTargets")
.param("offset", "1").param("limit", "2").param("sort", "name:DESC")
.param("q", "controllerId==target*").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(requestParameters(
parameterWithName("limit").attributes(key("type").value("query"))
.description(ApiModelPropertiesGeneric.LIMIT),
parameterWithName("sort").description(ApiModelPropertiesGeneric.SORT),
parameterWithName("offset").description(ApiModelPropertiesGeneric.OFFSET),
parameterWithName("q").description(ApiModelPropertiesGeneric.FIQL))));
}
@Test
@Description("Handles the GET request for retrieving installed targets of a single distribution set. Required Permission: "
+ SpPermission.READ_REPOSITORY + " and " + SpPermission.READ_TARGET)
public void getInstalledTargets() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
final Target target = testdataFactory.createTarget();
// assign knownTargetId to distribution set
assignDistributionSet(set.getId(), target.getControllerId());
// make it in install state
testdataFactory.sendUpdateActionStatusToTargets(Arrays.asList(target), Status.FINISHED, "some message");
mockMvc.perform(
get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/installedTargets",
set.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(
pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_LIST)
.type("Array[Object]"))));
}
@Test
@Description("Handles the POST request for assigning multiple targets to a distribution set.The request body must always be a list of target IDs."
+ " Required Permission: " + SpPermission.READ_REPOSITORY + " and " + SpPermission.UPDATE_TARGET)
public void createAssignedTarget() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
// prepare targets
final long forceTime = System.currentTimeMillis();
final String[] knownTargetIds = new String[] { "target1", "target2", "target3", "target4", "target5" };
final JSONArray list = new JSONArray();
for (final String targetId : knownTargetIds) {
targetManagement.create(entityFactory.target().create().controllerId(targetId));
list.put(new JSONObject().put("id", targetId).put("type", "timeforced").put("forcetime", forceTime).put(
"maintenanceWindow",
getMaintenanceWindow(getTestSchedule(10), getTestDuration(10), getTestTimeZone())));
}
// assign already one target to DS
assignDistributionSet(set.getId(), knownTargetIds[0]);
this.mockMvc
.perform(post(
MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/assignedTargets",
set.getId()).content(list.toString()).contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestParameters(parameterWithName("offline")
.description(MgmtApiModelProperties.OFFLINE_UPDATE).optional()),
requestFields(requestFieldWithPath("[]forcetime").description(MgmtApiModelProperties.FORCETIME),
requestFieldWithPath("[]id").description(ApiModelPropertiesGeneric.ITEM_ID),
requestFieldWithPath("[]maintenanceWindow")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW).optional(),
requestFieldWithPath("[]maintenanceWindow.schedule")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_SCHEDULE).optional(),
requestFieldWithPath("[]maintenanceWindow.duration")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_DURATION).optional(),
requestFieldWithPath("[]maintenanceWindow.timezone")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_TIMEZONE).optional(),
requestFieldWithPath("[]type").description(MgmtApiModelProperties.FORCETIME_TYPE)
.attributes(key("value").value("['soft', 'forced','timeforced']"))),
responseFields(
fieldWithPath("assigned").description(MgmtApiModelProperties.DS_NEW_ASSIGNED_TARGETS),
fieldWithPath("alreadyAssigned").type(JsonFieldType.NUMBER)
.description(MgmtApiModelProperties.DS_ALREADY_ASSIGNED_TARGETS),
fieldWithPath("total").type(JsonFieldType.NUMBER)
.description(MgmtApiModelProperties.DS_TOTAL_ASSIGNED_TARGETS))));
}
@Test
@Description("Handles the POST request for assigning multiple software modules to a distribution set. The request body must always be a list of software module IDs."
+ " Required Permission: " + SpPermission.READ_REPOSITORY + " and " + SpPermission.UPDATE_REPOSITORY)
public void assignSoftwareModules() throws Exception {
// create DisSet
final DistributionSet disSet = testdataFactory.createDistributionSetWithNoSoftwareModules("Jupiter", "398,88");
// create Software Modules
final List<Long> smIDs = Arrays.asList(testdataFactory.createSoftwareModuleOs().getId(),
testdataFactory.createSoftwareModuleApp().getId());
final JSONArray list = new JSONArray();
for (final Long smID : smIDs) {
list.put(new JSONObject().put("id", Long.valueOf(smID)));
}
// post assignment
mockMvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/assignedSM",
disSet.getId()).contentType(MediaType.APPLICATION_JSON_UTF8).content(list.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(requestFieldWithPath("[]id").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Delete a software module assignment." + " Required Permission: " + SpPermission.UPDATE_REPOSITORY)
public void deleteAssignSoftwareModules() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
mockMvc.perform(delete(
MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING
+ "/{distributionSetId}/assignedSM/{softwareModuleId}",
set.getId(), set.findFirstModuleByType(osType).get().getId())
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID))));
;
}
@Test
@Description("Handles the GET request of retrieving assigned software modules of a single distribution set within SP. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getAssignedSoftwareModules() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
// post assignment
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/assignedSM",
set.getId()).accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(
pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.SM_LIST),
fieldWithPath("content[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("content[].name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("content[].description")
.description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("content[].vendor").description(MgmtApiModelProperties.VENDOR),
fieldWithPath("content[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("content[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("content[].lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath("content[].lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath("content[].type").description(MgmtApiModelProperties.SM_TYPE),
fieldWithPath("content[].version").description(MgmtApiModelProperties.VERSION),
fieldWithPath("content[]._links.self").ignored())));
}
@Test
@Description("Handles the GET request of retrieving assigned software modules of a single distribution set within SP with given page size and offset including sorting by version descending and filter down to all sets which name starts with 'one'. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getAssignedSoftwareModulesWithParameters() throws Exception {
final DistributionSet set = testdataFactory.createUpdatedDistributionSet();
// post assignment
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + set.getId() + "/assignedSM")
.param("offset", "1").param("limit", "2").param("sort", "version:DESC").param("q", "name==one*")
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(this.document.document(requestParameters(
parameterWithName("limit").attributes(key("type").value("query"))
.description(ApiModelPropertiesGeneric.LIMIT),
parameterWithName("sort").description(ApiModelPropertiesGeneric.SORT),
parameterWithName("offset").description(ApiModelPropertiesGeneric.OFFSET),
parameterWithName("q").description(ApiModelPropertiesGeneric.FIQL))));
}
@Test
@Description("Get a paged list of meta data for a distribution set with standard page size."
+ " Required Permission: " + SpPermission.READ_REPOSITORY)
public void getMetadata() throws Exception {
final int totalMetadata = 4;
final String knownKeyPrefix = "knownKey";
final String knownValuePrefix = "knownValue";
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
for (int index = 0; index < totalMetadata; index++) {
distributionSetManagement.createMetaData(testDS.getId(), Lists
.newArrayList(entityFactory.generateMetadata(knownKeyPrefix + index, knownValuePrefix + index)));
}
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/metadata",
testDS.getId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.META_DATA),
fieldWithPath("content[].key").description(MgmtApiModelProperties.META_DATA_KEY),
fieldWithPath("content[].value").description(MgmtApiModelProperties.META_DATA_VALUE))));
}
@Test
@Description("Get a paged list of meta data for a distribution set with defined page size and sorting by name descending and key starting with 'known'."
+ " Required Permission: " + SpPermission.READ_REPOSITORY)
public void getMetadataWithParameters() throws Exception {
final int totalMetadata = 4;
final String knownKeyPrefix = "knownKey";
final String knownValuePrefix = "knownValue";
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
for (int index = 0; index < totalMetadata; index++) {
distributionSetManagement.createMetaData(testDS.getId(), Lists
.newArrayList(entityFactory.generateMetadata(knownKeyPrefix + index, knownValuePrefix + index)));
}
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{dsId}/metadata", testDS.getId())
.param("offset", "1").param("limit", "2").param("sort", "key:DESC").param("q", "key==known*"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
requestParameters(
parameterWithName("limit").attributes(key("type").value("query"))
.description(ApiModelPropertiesGeneric.LIMIT),
parameterWithName("sort").description(ApiModelPropertiesGeneric.SORT),
parameterWithName("offset").description(ApiModelPropertiesGeneric.OFFSET),
parameterWithName("q").description(ApiModelPropertiesGeneric.FIQL)),
responseFields(fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.META_DATA),
fieldWithPath("content[].key").description(MgmtApiModelProperties.META_DATA_KEY),
fieldWithPath("content[].value").description(MgmtApiModelProperties.META_DATA_VALUE))));
}
@Test
@Description("Get a single meta data value for a meta data key." + " Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getMetadataValue() throws Exception {
// prepare and create metadata
final String knownKey = "knownKey";
final String knownValue = "knownValue";
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
distributionSetManagement.createMetaData(testDS.getId(),
Arrays.asList(entityFactory.generateMetadata(knownKey, knownValue)));
mockMvc.perform(get(
MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/metadata/{metadatakey}",
testDS.getId(), knownKey)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("metadatakey").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("key").description(MgmtApiModelProperties.META_DATA_KEY),
fieldWithPath("value").description(MgmtApiModelProperties.META_DATA_VALUE))));
}
@Test
@Description("Update a single meta data value for speficic key." + " Required Permission: "
+ SpPermission.UPDATE_REPOSITORY)
public void updateMetadata() throws Exception {
// prepare and create metadata for update
final String knownKey = "knownKey";
final String knownValue = "knownValue";
final String updateValue = "valueForUpdate";
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
distributionSetManagement.createMetaData(testDS.getId(),
Arrays.asList(entityFactory.generateMetadata(knownKey, knownValue)));
final JSONObject jsonObject = new JSONObject().put("key", knownKey).put("value", updateValue);
mockMvc.perform(put(
MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/metadata/{metadatakey}",
testDS.getId(), knownKey).contentType(MediaType.APPLICATION_JSON_UTF8).content(jsonObject.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("metadatakey").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(requestFieldWithPath("key").description(MgmtApiModelProperties.META_DATA_KEY),
requestFieldWithPath("value").description(MgmtApiModelProperties.META_DATA_VALUE)),
responseFields(fieldWithPath("key").description(MgmtApiModelProperties.META_DATA_KEY),
fieldWithPath("value").description(MgmtApiModelProperties.META_DATA_VALUE))));
}
@Test
@Description("Delete a single meta data." + " Required Permission: " + SpPermission.UPDATE_REPOSITORY)
public void deleteMetadata() throws Exception {
// prepare and create metadata for deletion
final String knownKey = "knownKey";
final String knownValue = "knownValue";
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
distributionSetManagement.createMetaData(testDS.getId(),
Arrays.asList(entityFactory.generateMetadata(knownKey, knownValue)));
mockMvc.perform(
delete(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/metadata/{key}",
testDS.getId(), knownKey))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("key").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Create a list of meta data entries" + " Required Permission: " + SpPermission.READ_REPOSITORY
+ " and " + SpPermission.UPDATE_TARGET)
public void createMetadata() throws Exception {
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
final String knownKey1 = "knownKey1";
final String knownKey2 = "knownKey2";
final String knownValue1 = "knownValue1";
final String knownValue2 = "knownValue2";
final JSONArray jsonArray = new JSONArray();
jsonArray.put(new JSONObject().put("key", knownKey1).put("value", knownValue1));
jsonArray.put(new JSONObject().put("key", knownKey2).put("value", knownValue2));
mockMvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/metadata",
testDS.getId()).contentType(MediaType.APPLICATION_JSON_UTF8).content(jsonArray.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(requestFieldWithPath("[]key").description(MgmtApiModelProperties.META_DATA_KEY),
optionalRequestFieldWithPath("[]value")
.description(MgmtApiModelProperties.META_DATA_VALUE))));
}
}

View File

@@ -0,0 +1,597 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.mgmt.documentation;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.snippet.Attributes.key;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessAction;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.documentation.DocumenationResponseFieldsSnippet;
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.PageRequest;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.FieldDescriptor;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.restdocs.snippet.Snippet;
import com.fasterxml.jackson.core.JsonProcessingException;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Documentation generation for Rollout API for {@link Rollout}.
*
*/
@Features("Spring Rest Docs Tests - Rollout")
@Stories("Rollout Resource")
public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentation {
@Override
@Before
public void setUp() {
this.resourceName = "rollouts";
super.setUp();
arrayPrefix = "content[].";
}
@Test
@Description("Handles the GET request of retrieving all rollouts. Required Permission: "
+ SpPermission.READ_ROLLOUT)
public void getRollouts() throws Exception {
createRolloutEntity();
mockMvc.perform(get(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(getRolloutResponseFields(true, false,
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER).description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.ROLLOUT_LIST))));
}
@Test
@Description("Handles the GET request of retrieving all rollouts. Required Permission: "
+ SpPermission.READ_ROLLOUT)
public void getRolloutsWithParameters() throws Exception {
createRolloutEntity();
mockMvc.perform(get(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING).param("offset", "0").param("limit", "2")
.param("sort", "id:DESC").param("q", "name==exampleRollout*").accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(getFilterRequestParamter()));
}
private Snippet getRolloutResponseFields(final boolean isArray, final boolean withDetails,
final FieldDescriptor... descriptors) throws JsonProcessingException {
final String arrayPrefix = getArrayPrefix(isArray);
final List<FieldDescriptor> allFieldDescriptor = new ArrayList<>();
allFieldDescriptor.addAll(Arrays.asList(descriptors));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "id").description(ApiModelPropertiesGeneric.ITEM_ID));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "name").description(ApiModelPropertiesGeneric.NAME));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "deleted").description(ApiModelPropertiesGeneric.DELETED));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "description").description(ApiModelPropertiesGeneric.DESCRPTION));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "createdBy").description(ApiModelPropertiesGeneric.CREATED_BY));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "createdAt").description(ApiModelPropertiesGeneric.CREATED_AT));
allFieldDescriptor.add(
fieldWithPath(arrayPrefix + "lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY));
allFieldDescriptor.add(
fieldWithPath(arrayPrefix + "lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "targetFilterQuery")
.description(MgmtApiModelProperties.ROLLOUT_FILTER_QUERY));
allFieldDescriptor.add(
fieldWithPath(arrayPrefix + "distributionSetId").description(MgmtApiModelProperties.ROLLOUT_DS_ID));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "status").description(MgmtApiModelProperties.ROLLOUT_STATUS)
.attributes(key("value").value("['creating','ready','paused','running','finished']")));
allFieldDescriptor.add(
fieldWithPath(arrayPrefix + "totalTargets").description(MgmtApiModelProperties.ROLLOUT_TOTAL_TARGETS));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.self").ignored());
if (withDetails) {
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "totalTargetsPerStatus")
.description(MgmtApiModelProperties.ROLLOUT_TOTAL_TARGETS_PER_STATUS));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.start")
.description(MgmtApiModelProperties.ROLLOUT_LINKS_START_SYNC));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.pause")
.description(MgmtApiModelProperties.ROLLOUT_LINKS_PAUSE));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.resume")
.description(MgmtApiModelProperties.ROLLOUT_LINKS_RESUME));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.groups")
.description(MgmtApiModelProperties.ROLLOUT_LINKS_GROUPS));
}
return new DocumenationResponseFieldsSnippet(allFieldDescriptor);
}
@Test
@Description("Handles the GET request of retrieving a single rollout. Required Permission: "
+ SpPermission.READ_ROLLOUT)
public void getRollout() throws Exception {
final Rollout rollout = createRolloutEntity();
mockMvc.perform(get(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}", rollout.getId())
.accept(MediaTypes.HAL_JSON_VALUE)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(getRolloutResponseFields(false, true),
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the POST request of creating a rollout. Required Permission: " + SpPermission.CREATE_ROLLOUT)
public void createRollout() throws Exception {
testdataFactory.createTargets(20, "targets-");
final String name = "exampleRollout";
final String description = "Rollout for all named targets";
final int groupSize = 10;
final Long dsId = testdataFactory.createDistributionSet().getId();
final String targetFilter = "id==targets-*";
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "50")
.successAction(RolloutGroupSuccessAction.NEXTGROUP, "")
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, "80")
.errorAction(RolloutGroupErrorAction.PAUSE, "").build();
mockMvc.perform(post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING)
.content(JsonBuilder.rollout(name, description, groupSize, dsId, targetFilter, rolloutGroupConditions))
.contentType(APPLICATION_JSON_HAL_UTF).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(requestFields(
requestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPath("distributionSetId").description(MgmtApiModelProperties.ROLLOUT_DS_ID),
requestFieldWithPath("targetFilterQuery")
.description(MgmtApiModelProperties.ROLLOUT_FILTER_QUERY),
requestFieldWithPath("amountGroups").description(MgmtApiModelProperties.ROLLOUT_AMOUNT_GROUPS),
optionalRequestFieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("successCondition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION),
optionalRequestFieldWithPath("successCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("successCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_EXP),
optionalRequestFieldWithPath("successAction")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION),
optionalRequestFieldWithPath("successAction.action")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_ACTION)
.attributes(key("value").value("['nextgroup']")),
optionalRequestFieldWithPath("successAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_EXP),
optionalRequestFieldWithPath("errorCondition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION),
optionalRequestFieldWithPath("errorCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("errorCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_EXP),
optionalRequestFieldWithPath("errorAction")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION),
optionalRequestFieldWithPath("errorAction.action")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_ACTION)
.attributes(key("value").value("['pause']")),
optionalRequestFieldWithPath("errorAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_EXP)),
getRolloutResponseFields(false, true)));
}
@Test
@Description("Handles the POST request of creating a rollout with a groups definition. Required Permission: "
+ SpPermission.CREATE_ROLLOUT)
public void createRolloutWithGroupsDefinition() throws Exception {
final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "targets-", "rollout");
final List<RolloutGroup> rolloutGroups = new ArrayList<>(2);
final float percentTargetsInGroup1 = 20;
final float percentTargetsInGroup2 = 100;
final RolloutGroup group1 = entityFactory.rolloutGroup().create().name("Group1").description("Group1desc")
.targetFilterQuery("name==targets-1*").targetPercentage(percentTargetsInGroup1)
.conditions(new RolloutGroupConditionBuilder()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "90")
.successAction(RolloutGroupSuccessAction.NEXTGROUP, "")
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, "30")
.errorAction(RolloutGroupErrorAction.PAUSE, "").build())
.build();
rolloutGroups.add(group1);
final RolloutGroup group2 = entityFactory.rolloutGroup().create().name("Group2").description("Group2desc")
.targetPercentage(percentTargetsInGroup2).build();
rolloutGroups.add(group2);
final String name = "exampleRolloutWithDefinedGroups";
final String description = "Rollout for all named targets";
final Long dsId = testdataFactory.createDistributionSet().getId();
final String targetFilter = "id==targets-*";
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "50")
.successAction(RolloutGroupSuccessAction.NEXTGROUP, "")
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, "80")
.errorAction(RolloutGroupErrorAction.PAUSE, "").build();
mockMvc.perform(
post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING)
.content(JsonBuilder.rollout(name, description, null, dsId, targetFilter,
rolloutGroupConditions, rolloutGroups))
.contentType(MediaType.APPLICATION_JSON).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(requestFields(
requestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPath("distributionSetId").description(MgmtApiModelProperties.ROLLOUT_DS_ID),
requestFieldWithPath("targetFilterQuery")
.description(MgmtApiModelProperties.ROLLOUT_FILTER_QUERY),
optionalRequestFieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("successCondition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION),
optionalRequestFieldWithPath("successCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("successCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_EXP),
optionalRequestFieldWithPath("successAction")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION),
optionalRequestFieldWithPath("successAction.action")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_ACTION)
.attributes(key("value").value("['nextgroup']")),
optionalRequestFieldWithPath("successAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_EXP),
optionalRequestFieldWithPath("errorCondition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION),
optionalRequestFieldWithPath("errorCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("errorCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_EXP),
optionalRequestFieldWithPath("errorAction")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION),
optionalRequestFieldWithPath("errorAction.action")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_ACTION)
.attributes(key("value").value("['pause']")),
optionalRequestFieldWithPath("errorAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_EXP),
requestFieldWithPath("groups").description(MgmtApiModelProperties.ROLLOUT_GROUPS),
requestFieldWithPath("groups[].name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPath("groups[].description").description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("groups[].targetFilterQuery")
.description(MgmtApiModelProperties.ROLLOUT_GROUP_FILTER_QUERY),
optionalRequestFieldWithPath("groups[].targetPercentage")
.description(MgmtApiModelProperties.ROLLOUT_GROUP_TARGET_PERCENTAGE)
.attributes(key("value").value("0..100")),
optionalRequestFieldWithPath("groups[].successCondition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION),
optionalRequestFieldWithPath("groups[].successCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("groups[].successCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_EXP),
optionalRequestFieldWithPath("groups[].successAction")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION),
optionalRequestFieldWithPath("groups[].successAction.action")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_ACTION)
.attributes(key("value").value("['nextgroup']")),
optionalRequestFieldWithPath("groups[].successAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_EXP),
optionalRequestFieldWithPath("groups[].errorCondition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION),
optionalRequestFieldWithPath("groups[].errorCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("groups[].errorCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_EXP),
optionalRequestFieldWithPath("groups[].errorAction")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION),
optionalRequestFieldWithPath("groups[].errorAction.action")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_ACTION)
.attributes(key("value").value("['pause']")),
optionalRequestFieldWithPath("groups[].errorAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_EXP)),
getRolloutResponseFields(false, true)));
}
@Test
@Description("Handles the DELETE request of deleting a rollout within SP. Required Permission: "
+ SpPermission.DELETE_ROLLOUT)
public void deleteRollout() throws Exception {
final Rollout rollout = createRolloutEntity();
this.mockMvc.perform(delete(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}", rollout.getId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print()).andDo(this.document.document(
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.NAME))));
}
@Test
@Description("Handles the POST request of starting a rollout. Required Permission: " + SpPermission.HANDLE_ROLLOUT)
public void startRollout() throws Exception {
final Rollout rollout = createRolloutEntity();
mockMvc.perform(post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/start", rollout.getId())
.accept(MediaTypes.HAL_JSON_VALUE)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the POST request of pausing a rollout. Required Permission: " + SpPermission.HANDLE_ROLLOUT)
public void pauseRollout() throws Exception {
final Rollout rollout = createRolloutEntity();
rolloutManagement.start(rollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
mockMvc.perform(post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/pause", rollout.getId())
.accept(MediaTypes.HAL_JSON_VALUE)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the POST request of resuming a rollout. Required Permission: " + SpPermission.HANDLE_ROLLOUT)
public void resumeRollout() throws Exception {
final Rollout rollout = createRolloutEntity();
rolloutManagement.start(rollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutManagement.pauseRollout(rollout.getId());
mockMvc.perform(post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/resume", rollout.getId())
.accept(MediaTypes.HAL_JSON_VALUE)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving the deploy groups of a rollout. Required Permission: "
+ SpPermission.READ_ROLLOUT)
public void getRolloutDeployGroups() throws Exception {
final Rollout rollout = createRolloutEntity();
mockMvc.perform(get(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/deploygroups", rollout.getId())
.accept(MediaTypes.HAL_JSON_VALUE)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
getRolloutDeployGroupResponseFields(true, false,
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.ROLLOUT_LIST)),
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving a deploy group of a rollout. Required Permission: "
+ SpPermission.READ_ROLLOUT)
public void getRolloutDeployGroup() throws Exception {
final Rollout rollout = createRolloutEntity();
final RolloutGroup firstRolloutGroup = rolloutGroupManagement.findByRollout(PAGE, rollout.getId()).getContent()
.get(0);
mockMvc.perform(get(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/deploygroups/{deployGroupId}",
rollout.getId(), firstRolloutGroup.getId()).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(getRolloutDeployGroupResponseFields(false, true),
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("deployGroupId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
private Snippet getRolloutDeployGroupResponseFields(final boolean isArray, final boolean withDetails,
final FieldDescriptor... descriptors) throws JsonProcessingException {
final String arrayPrefix = getArrayPrefix(isArray);
final List<FieldDescriptor> allFieldDescriptor = new ArrayList<>();
allFieldDescriptor.addAll(Arrays.asList(descriptors));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "id").description(ApiModelPropertiesGeneric.ITEM_ID));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "name").description(ApiModelPropertiesGeneric.NAME));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "description").optional()
.description(ApiModelPropertiesGeneric.DESCRPTION));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "createdBy").description(ApiModelPropertiesGeneric.CREATED_BY));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "createdAt").description(ApiModelPropertiesGeneric.CREATED_AT));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "lastModifiedBy").optional().type(JsonFieldType.STRING)
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "lastModifiedAt").optional().type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "status").description(MgmtApiModelProperties.ROLLOUT_GROUP_STATUS)
.attributes(key("value").value("['creating','ready','paused','running','finished']")));
allFieldDescriptor.add(
fieldWithPath(arrayPrefix + "totalTargets").description(MgmtApiModelProperties.ROLLOUT_TOTAL_TARGETS));
if (withDetails) {
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "totalTargetsPerStatus")
.description(MgmtApiModelProperties.ROLLOUT_TOTAL_TARGETS_PER_STATUS));
}
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "targetFilterQuery")
.description(MgmtApiModelProperties.ROLLOUT_GROUP_FILTER_QUERY));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "targetPercentage")
.description(MgmtApiModelProperties.ROLLOUT_GROUP_TARGET_PERCENTAGE));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "successCondition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "successCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_CONDITION));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "successCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_EXP));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "successAction")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "successAction.action")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_ACTION));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "successAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_EXP));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "errorCondition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "errorCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_CONDITION));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "errorCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_EXP));
allFieldDescriptor.add(
fieldWithPath(arrayPrefix + "errorAction").description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "errorAction.action")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_ACTION));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "errorAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_EXP));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.self").ignored());
return new DocumenationResponseFieldsSnippet(allFieldDescriptor);
}
@Test
@Description("Handles the GET request of retrieving a deploy group of a rollout. Required Permission: "
+ SpPermission.READ_ROLLOUT)
public void getRolloutDeployGroupWithParameters() throws Exception {
final Rollout rollout = createRolloutEntity();
final RolloutGroup firstRolloutGroup = rolloutGroupManagement
.findByRollout(new PageRequest(0, 1), rollout.getId()).getContent().get(0);
mockMvc.perform(get(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/deploygroups/{deployGroupId}",
rollout.getId(), firstRolloutGroup.getId()).param("offset", "0").param("limit", "2")
.param("sort", "id:DESC").param("q", "id==" + firstRolloutGroup.getId())
.accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("deployGroupId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getFilterRequestParamter()));
}
@Test
@Description("Handles the GET request of retrieving a all targets of a specific deploy group of a rollout. Required Permissions: "
+ SpPermission.READ_ROLLOUT + ", " + SpPermission.READ_TARGET)
public void getRolloutDeployGroupTargets() throws Exception {
final Rollout rollout = createRolloutEntity();
final RolloutGroup firstRolloutGroup = rolloutGroupManagement
.findByRollout(new PageRequest(0, 1), rollout.getId()).getContent().get(0);
mockMvc.perform(
get(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/deploygroups/{deployGroupId}/targets",
rollout.getId(), firstRolloutGroup.getId()).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("deployGroupId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_LIST),
fieldWithPath("content[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("content[].address").optional().type(String.class)
.description(MgmtApiModelProperties.ADDRESS),
fieldWithPath("content[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("content[].name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("content[].description").optional().type(String.class)
.description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("content[].controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("content[].updateStatus")
.description(MgmtApiModelProperties.UPDATE_STATUS).type("enum")
.attributes(key("value")
.value("['error', 'in_sync', 'pending', 'registered', 'unknown']")),
fieldWithPath("content[].securityToken")
.description(MgmtApiModelProperties.SECURITY_TOKEN),
fieldWithPath("content[].installedAt").optional().type(Long.class)
.description(MgmtApiModelProperties.INSTALLED_AT),
fieldWithPath("content[].lastModifiedAt").optional().type(Long.class)
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
fieldWithPath("content[].lastModifiedBy").optional().type(String.class)
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
fieldWithPath("content[].ipAddress").optional().type(String.class)
.description(MgmtApiModelProperties.IP_ADDRESS).type("String"),
fieldWithPath("content[].lastControllerRequestAt").optional().type(Long.class)
.description(MgmtApiModelProperties.LAST_REQUEST_AT).type("Number"),
fieldWithPath("content[]._links.self").ignored())));
}
@Test
@Description("Handles the GET request of retrieving a all targets of a specific deploy group of a rollout. Required Permission: "
+ SpPermission.READ_ROLLOUT + ", " + SpPermission.READ_TARGET)
public void getRolloutDeployGroupTargetsWithParameters() throws Exception {
final Rollout rollout = createRolloutEntity();
final RolloutGroup firstRolloutGroup = rolloutGroupManagement
.findByRollout(new PageRequest(0, 1), rollout.getId()).getContent().get(0);
mockMvc.perform(
get(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/deploygroups/{deployGroupId}/targets",
rollout.getId(), firstRolloutGroup.getId()).param("offset", "0").param("limit", "2")
.param("sort", "name:ASC").param("q", "controllerId==exampleTarget0")
.accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("deployGroupId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getFilterRequestParamter()));
}
private Rollout createRolloutEntity() {
testdataFactory.createTargets(20, "exampleTarget");
final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name("exampleRollout")
.targetFilterQuery("controllerId==exampleTarget*").set(testdataFactory.createDistributionSet()),
10, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "10").build());
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();
return rolloutManagement
.update(entityFactory.rollout().update(rollout.getId()).description("exampleDescription"));
}
}

View File

@@ -0,0 +1,220 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.mgmt.documentation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.Arrays;
import java.util.List;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
*
* Documentation generation for Management API for {@link SoftwareModuleType}.
*
*/
@Features("Spring Rest Docs Tests - SoftwareModuleType")
@Stories("Softwaremoduletypes Resource")
public class SoftwaremoduleTypesDocumentationTest extends AbstractApiRestDocumentation {
@Override
@Before
public void setUp() {
this.resourceName = "softwaremoduletypes";
super.setUp();
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Handles the GET request of retrieving all software module types within SP. Required Permission: READ_REPOSITORY.")
public void getSoftwareModuleTypes() throws Exception {
final SoftwareModuleType testType = testdataFactory.findOrCreateSoftwareModuleType("test123");
softwareModuleTypeManagement
.update(entityFactory.softwareModuleType().update(testType.getId()).description("Desc1234"));
mockMvc.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(responseFields(
fieldWithPath("size").type(JsonFieldType.NUMBER).description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_LIST),
fieldWithPath("content[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("content[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("content[].description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("content[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("content[].lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
fieldWithPath("content[].lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
fieldWithPath("content[].name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("content[]._links.self").ignored())));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Handles the GET request of retrieving all software module types within SP with parametsrs. In this case the first 10 result in ascending order by name wher the name starts with 'a'. Required Permission: READ_REPOSITORY.")
public void getSoftwareModuleTypesWithParameters() throws Exception {
final SoftwareModuleType testType = testdataFactory.findOrCreateSoftwareModuleType("test123");
softwareModuleTypeManagement
.update(entityFactory.softwareModuleType().update(testType.getId()).description("Desc1234"));
mockMvc.perform(get(
MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING + "?limit=10&sort=name:ASC&offset=0&q=name==a")
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(getFilterRequestParamter()));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Handles the POST request of creating new software module types within SP. The request body must "
+ "always be a list of module types. Required Permission: CREATE_REPOSITORY.")
public void postSoftwareModuleTypes() throws Exception {
final List<SoftwareModuleType> types = Arrays.asList(entityFactory.softwareModuleType().create().key("test1")
.name("TestName1").description("Desc1").build());
this.mockMvc
.perform(post(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING)
.content(JsonBuilder.softwareModuleTypesCreatableFieldsOnly(types))
.contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
requestFields(
optionalRequestFieldWithPath("[]description")
.description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("[]key").description(MgmtApiModelProperties.SMT_KEY),
optionalRequestFieldWithPath("[]maxAssignments")
.description(MgmtApiModelProperties.SM_MAX_ASSIGNMENTS),
requestFieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME)),
responseFields(fieldWithPath("[]key").description(MgmtApiModelProperties.SMT_KEY),
fieldWithPath("[]maxAssignments")
.description(MgmtApiModelProperties.SMT_MAX_ASSIGNMENTS),
fieldWithPath("[]createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("[]createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("[]description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("[]deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("[]id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("[]lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
fieldWithPath("[]lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
fieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("[]_links.self").ignored())));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Handles the DELETE request for a single software module Type within SP. Required Permission: DELETE_REPOSITORY.")
public void deleteSoftwareModuleType() throws Exception {
final SoftwareModuleType testType = softwareModuleTypeManagement.create(
entityFactory.softwareModuleType().create().key("test1").name("TestName1").description("Desc1"));
assertThat(softwareModuleTypeManagement.count()).isEqualTo(4);
this.mockMvc
.perform(delete(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING + "/{softwareModuleTypeID}",
testType.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(pathParameters(
parameterWithName("softwareModuleTypeID").description(ApiModelPropertiesGeneric.ITEM_ID))));
assertThat(softwareModuleTypeManagement.count()).isEqualTo(3);
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Handles the GET request of retrieving a single software module type within SP. Required Permission: READ_REPOSITORY.")
public void getSoftwareModuleType() throws Exception {
final SoftwareModuleType testType = testdataFactory.findOrCreateSoftwareModuleType("test123");
softwareModuleTypeManagement
.update(entityFactory.softwareModuleType().update(testType.getId()).description("Desc1234"));
this.mockMvc
.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING + "/{softwareModuleTypeID}",
testType.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("softwareModuleTypeID")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("key").description(MgmtApiModelProperties.SMT_KEY),
fieldWithPath("maxAssignments").description(MgmtApiModelProperties.SMT_MAX_ASSIGNMENTS),
fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
.type("Number"),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
.type("String"),
fieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("_links.self").ignored())));
}
@Test
@Description("Handles the PUT request for a single software module type within SP. Required Permission: UPDATE_REPOSITORY.")
public void putSoftwareModuleType() throws Exception {
final SoftwareModuleType testType = testdataFactory.findOrCreateSoftwareModuleType("test123");
final String body = new JSONObject().put("description", "a new description").toString();
this.mockMvc
.perform(put(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING + "/{softwareModuleTypeID}",
testType.getId()).content(body.toString()).contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("softwareModuleTypeID")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(
requestFieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION)),
responseFields(fieldWithPath("key").description(MgmtApiModelProperties.SMT_KEY),
fieldWithPath("maxAssignments").description(MgmtApiModelProperties.SMT_MAX_ASSIGNMENTS),
fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
.type("Number"),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
.type("String"),
fieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("_links.self").ignored())));
}
}

View File

@@ -0,0 +1,580 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.mgmt.documentation;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.fileUpload;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.restdocs.snippet.Attributes.key;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.Constants;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.restdocs.payload.JsonFieldType;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Documentation generation for Management API for {@link SoftwareModule}.
*/
@Features("Spring Rest Docs Tests - SoftwareModule")
@Stories("Softwaremodule Resource")
public class SoftwaremodulesDocumentationTest extends AbstractApiRestDocumentation {
@Override
@Before
public void setUp() {
resourceName = "softwaremodules";
super.setUp();
}
@Test
@Description("Handles the GET request of retrieving all softwaremodules within SP. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getSoftwareModules() throws Exception {
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
softwareModuleManagement.update(entityFactory.softwareModule().update(sm.getId()).description("a description"));
final SoftwareModule sm2 = testdataFactory.createSoftwareModuleApp();
softwareModuleManagement
.update(entityFactory.softwareModule().update(sm2.getId()).description("a description"));
mockMvc.perform(get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(responseFields(
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER).description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.SM_LIST),
fieldWithPath("content[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("content[].name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("content[].description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("content[].vendor").description(MgmtApiModelProperties.VENDOR),
fieldWithPath("content[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("content[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("content[].lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath("content[].lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath("content[].type").description(MgmtApiModelProperties.SM_TYPE),
fieldWithPath("content[].version").description(MgmtApiModelProperties.VERSION),
fieldWithPath("content[]._links.self").ignored())));
}
@Test
@Description("Handles the GET request of retrieving all softwaremodules within SP with given page size and offset including sorting by version descending and filter down to all sets which name starts with 'SM'. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getSoftwareModulesWithParameters() throws Exception {
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
softwareModuleManagement.update(entityFactory.softwareModule().update(sm.getId()).description("a description"));
final SoftwareModule sm2 = testdataFactory.createSoftwareModuleApp();
softwareModuleManagement
.update(entityFactory.softwareModule().update(sm2.getId()).description("a description"));
mockMvc.perform(get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING).param("offset", "1")
.param("limit", "2").param("sort", "version:DESC").param("q", "name==SM*"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(getFilterRequestParamter()));
}
@Test
@Description("Handles the POST request of creating new software modules within SP. The request body must always be a list of modules. Required Permission: "
+ SpPermission.CREATE_REPOSITORY)
public void postSoftwareModules() throws Exception {
final SoftwareModule os = entityFactory.softwareModule().create().type(osType).name("name1").version("version1")
.description("description1").vendor("vendor1").build();
final SoftwareModule ah = entityFactory.softwareModule().create().type(appType).name("name3")
.version("version1").description("description1").vendor("vendor1").build();
final List<SoftwareModule> modules = Arrays.asList(os, ah);
mockMvc.perform(post(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING)
.content(JsonBuilder.softwareModulesCreatableFieldsOnly(modules)).contentType(APPLICATION_JSON_HAL_UTF))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
requestFields(requestFieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME),
optionalRequestFieldWithPath("[]description")
.description(ApiModelPropertiesGeneric.DESCRPTION),
requestFieldWithPath("[]version").description(MgmtApiModelProperties.VERSION),
optionalRequestFieldWithPath("[]vendor").description(MgmtApiModelProperties.VENDOR),
requestFieldWithPath("[]type").description(MgmtApiModelProperties.SMT_TYPE)),
responseFields(fieldWithPath("[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("[].name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("[].description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("[].vendor").description(MgmtApiModelProperties.VENDOR),
fieldWithPath("[].deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("[].lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath("[].lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath("[].type").description(MgmtApiModelProperties.SM_TYPE),
fieldWithPath("[].version").description(MgmtApiModelProperties.VERSION),
fieldWithPath("[]._links.self").ignored())));
}
@Test
@Description("Handles the DELETE request for a single softwaremodule within SP. Required Permission: "
+ SpPermission.DELETE_REPOSITORY)
public void deleteSoftwareModule() throws Exception {
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
this.mockMvc
.perform(
delete(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}", sm.getId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving a single softwaremodule within SP. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getSoftwareModule() throws Exception {
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
softwareModuleManagement.update(entityFactory.softwareModule().update(sm.getId()).description("a description"));
mockMvc.perform(get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}", sm.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath("vendor").description(MgmtApiModelProperties.VENDOR),
fieldWithPath("deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("type").description(MgmtApiModelProperties.SM_TYPE),
fieldWithPath("version").description(MgmtApiModelProperties.VERSION),
fieldWithPath("_links.self").ignored(),
fieldWithPath("_links.type").description(MgmtApiModelProperties.SM_TYPE),
fieldWithPath("_links.artifacts").description(MgmtApiModelProperties.ARTIFACT_LIST),
fieldWithPath("_links.metadata").description(MgmtApiModelProperties.META_DATA))));
}
@Test
@Description("Handles the PUT request for a single softwaremodule within SP. Required Permission: "
+ SpPermission.UPDATE_REPOSITORY)
public void putSoftwareModule() throws Exception {
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
softwareModuleManagement.update(entityFactory.softwareModule().update(sm.getId()).description("a description"));
final SoftwareModule update = entityFactory.softwareModule().create().name("another name")
.vendor("another Vendor").description("a new description").type(Constants.SMT_DEFAULT_OS_KEY).build();
mockMvc.perform(put(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}", sm.getId())
.content(JsonBuilder.softwareModuleUpdatableFieldsOnly(update)).contentType(APPLICATION_JSON_HAL_UTF))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(optionalRequestFieldWithPath("vendor").description(MgmtApiModelProperties.VENDOR),
optionalRequestFieldWithPath("description")
.description(ApiModelPropertiesGeneric.DESCRPTION)),
responseFields(fieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath("type").description(MgmtApiModelProperties.SM_TYPE),
fieldWithPath("version").description(MgmtApiModelProperties.VERSION),
fieldWithPath("vendor").description(MgmtApiModelProperties.VENDOR),
fieldWithPath("deleted").description(ApiModelPropertiesGeneric.DELETED),
fieldWithPath("_links.self").ignored(),
fieldWithPath("_links.type").description(MgmtApiModelProperties.SM_TYPE),
fieldWithPath("_links.artifacts").description(MgmtApiModelProperties.ARTIFACT_LIST),
fieldWithPath("_links.metadata").description(MgmtApiModelProperties.META_DATA))));
}
@Test
@Description("Handles the GET request of retrieving all meta data of artifacts assigned to a software module. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getArtifacts() throws Exception {
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
final byte random[] = RandomStringUtils.random(5).getBytes();
artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1", false, 0);
mockMvc.perform(
get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/artifacts", sm.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("[].size").description(MgmtApiModelProperties.ARTIFACT_SIZE),
fieldWithPath("[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("[].lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath("[].lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath("[].hashes.md5").description(MgmtApiModelProperties.ARTIFACT_HASHES_MD5),
fieldWithPath("[].hashes.sha1")
.description(MgmtApiModelProperties.ARTIFACT_HASHES_SHA1),
fieldWithPath("[].providedFilename")
.description(MgmtApiModelProperties.ARTIFACT_PROVIDED_FILENAME),
fieldWithPath("[]._links.self").ignored())));
}
@Test
@Description("Handles POST request for artifact upload. Required Permission: " + SpPermission.CREATE_REPOSITORY)
public void postArtifact() throws Exception {
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
// create test file
final byte random[] = RandomStringUtils.random(5).getBytes();
final MockMultipartFile file = new MockMultipartFile("file", "origFilename", null, random);
mockMvc.perform(
fileUpload(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/artifacts",
sm.getId()).file(file))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("size").description(MgmtApiModelProperties.ARTIFACT_SIZE),
fieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath("_links.self").ignored(),
fieldWithPath("_links.download")
.description(MgmtApiModelProperties.ARTIFACT_DOWNLOAD_LINK),
fieldWithPath("hashes.md5").description(MgmtApiModelProperties.ARTIFACT_HASHES_MD5),
fieldWithPath("hashes.sha1").description(MgmtApiModelProperties.ARTIFACT_HASHES_SHA1),
fieldWithPath("providedFilename")
.description(MgmtApiModelProperties.ARTIFACT_PROVIDED_FILENAME)))
);
}
@Test
@Description("Handles POST request for artifact upload. Required Permission: " + SpPermission.CREATE_REPOSITORY)
public void postArtifactWithParameters() throws Exception {
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
final byte random[] = RandomStringUtils.random(5).getBytes();
final MockMultipartFile file = new MockMultipartFile("file", "origFilename", null, random);
mockMvc.perform(
fileUpload(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/artifacts",
sm.getId()).file(file).param("filename", "filename").param("file", "s")
.param("md5sum", "md5sum").param("sha1sum", "sha1sum"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(requestParameters(
parameterWithName("filename").description(MgmtApiModelProperties.ARTIFACT_PROVIDED_FILENAME),
parameterWithName("file").description(MgmtApiModelProperties.ARTIFACT_PROVIDED_FILE),
parameterWithName("md5sum").description(MgmtApiModelProperties.ARTIFACT_HASHES_MD5),
parameterWithName("sha1sum").description(MgmtApiModelProperties.ARTIFACT_HASHES_SHA1))));
}
@Test
@Description("Handles the DELETE request for a single SoftwareModule within SP. Required Permission: "
+ SpPermission.DELETE_REPOSITORY)
public void deleteArtifact() throws Exception {
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
final byte random[] = RandomStringUtils.random(5).getBytes();
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1",
false, 0);
mockMvc.perform(delete(
MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/artifacts/{artifactId}",
sm.getId(), artifact.getId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("artifactId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving a single Artifact meta data request. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getArtifact() throws Exception {
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
final byte random[] = RandomStringUtils.random(5).getBytes();
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1",
false, 0);
mockMvc.perform(
get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/artifacts/{artifactId}",
sm.getId(), artifact.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("artifactId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("size").description(MgmtApiModelProperties.ARTIFACT_SIZE),
fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath("hashes.md5").description(MgmtApiModelProperties.ARTIFACT_HASHES_MD5),
fieldWithPath("hashes.sha1").description(MgmtApiModelProperties.ARTIFACT_HASHES_SHA1),
fieldWithPath("providedFilename")
.description(MgmtApiModelProperties.ARTIFACT_PROVIDED_FILENAME),
fieldWithPath("_links.self").ignored(), fieldWithPath("_links.download")
.description(MgmtApiModelProperties.ARTIFACT_DOWNLOAD_LINK))));
}
@Test
@Description("Handles the GET request for downloading an artifact. Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getDownloadArtifact() throws Exception {
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
final byte random[] = RandomStringUtils.random(5).getBytes();
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1",
false, 0);
mockMvc.perform(get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING
+ "/{softwareModuleId}/artifacts/{artifactId}/download", sm.getId(), artifact.getId())
.accept(MediaType.APPLICATION_OCTET_STREAM))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM))
.andDo(this.document.document(pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("artifactId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description(" Get a paged list of meta data for a software module." + " Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getMetadata() throws Exception {
final int totalMetadata = 4;
final String knownKeyPrefix = "knownKey";
final String knownValuePrefix = "knownValue";
final SoftwareModule module = testdataFactory.createDistributionSet("one").findFirstModuleByType(osType).get();
for (int index = 0; index < totalMetadata; index++) {
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(module.getId())
.key(knownKeyPrefix + index).value(knownValuePrefix + index));
}
mockMvc.perform(get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/metadata",
module.getId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.META_DATA),
fieldWithPath("content[].key").description(MgmtApiModelProperties.META_DATA_KEY),
fieldWithPath("content[].value").description(MgmtApiModelProperties.META_DATA_VALUE),
fieldWithPath("content[].targetVisible")
.description(MgmtApiModelProperties.SM_META_DATA_TARGET_VISIBLE))));
}
@Test
@Description(" Get a paged list of meta data for a software module with defined page size and sorting by name descending and key starting with 'known'."
+ " Required Permission: " + SpPermission.READ_REPOSITORY)
public void getMetadataWithParameters() throws Exception {
final int totalMetadata = 4;
final String knownKeyPrefix = "knownKey";
final String knownValuePrefix = "knownValue";
final SoftwareModule module = testdataFactory.createDistributionSet("one").findFirstModuleByType(osType).get();
for (int index = 0; index < totalMetadata; index++) {
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(module.getId())
.key(knownKeyPrefix + index).value(knownValuePrefix + index));
}
mockMvc.perform(get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/metadata",
module.getId()).param("offset", "1").param("limit", "2").param("sort", "key:DESC").param("q",
"key==known*"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestParameters(
parameterWithName("limit").attributes(key("type").value("query"))
.description(ApiModelPropertiesGeneric.LIMIT),
parameterWithName("sort").description(ApiModelPropertiesGeneric.SORT),
parameterWithName("offset").description(ApiModelPropertiesGeneric.OFFSET),
parameterWithName("q").description(ApiModelPropertiesGeneric.FIQL))));
}
@Test
@Description("Create a list of meta data entries" + " Required Permission: " + SpPermission.UPDATE_REPOSITORY)
public void postMetadata() throws Exception {
final SoftwareModule module = testdataFactory.createDistributionSet("one").findFirstModuleByType(osType).get();
final String knownKey1 = "knownKey1";
final String knownKey2 = "knownKey2";
final String knownValue1 = "knownValue1";
final String knownValue2 = "knownValue2";
final JSONArray jsonArray = new JSONArray();
jsonArray.put(new JSONObject().put("key", knownKey1).put("value", knownValue1));
jsonArray.put(new JSONObject().put("key", knownKey2).put("value", knownValue2).put("targetVisible", true));
mockMvc.perform(post(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/metadata",
module.getId()).contentType(APPLICATION_JSON_HAL_UTF).content(jsonArray.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(requestFieldWithPath("[]key").description(MgmtApiModelProperties.META_DATA_KEY),
requestFieldWithPath("[]value").description(MgmtApiModelProperties.META_DATA_VALUE),
requestFieldWithPath("[]targetVisible")
.description(MgmtApiModelProperties.SM_META_DATA_TARGET_VISIBLE)),
responseFields(fieldWithPath("[]key").description(MgmtApiModelProperties.META_DATA_KEY),
fieldWithPath("[]value").description(MgmtApiModelProperties.META_DATA_VALUE),
fieldWithPath("[]targetVisible")
.description(MgmtApiModelProperties.SM_META_DATA_TARGET_VISIBLE)
)
));
}
@Test
@Description(" Delete a single meta data." + " Required Permission: " + SpPermission.UPDATE_REPOSITORY)
public void deleteMetadata() throws Exception {
// prepare and create metadata for deletion
final String knownKey = "knownKey";
final String knownValue = "knownValue";
final SoftwareModule module = testdataFactory.createDistributionSet("one").findFirstModuleByType(osType).get();
softwareModuleManagement.createMetaData(
entityFactory.softwareModuleMetadata().create(module.getId()).key(knownKey).value(knownValue));
mockMvc.perform(delete(
MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/metadata/{{metadataKey}",
module.getId(), knownKey)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("{metadataKey").description(MgmtApiModelProperties.META_DATA_KEY))));
}
@Test
@Description(" Get a single meta data value for a meta data key." + " Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getMetadataValue() throws Exception {
// prepare and create metadata
final String knownKey = "knownKey";
final String knownValue = "knownValue";
final SoftwareModule module = testdataFactory.createDistributionSet("one").findFirstModuleByType(osType).get();
softwareModuleManagement.createMetaData(
entityFactory.softwareModuleMetadata().create(module.getId()).key(knownKey).value(knownValue));
mockMvc.perform(
get(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/metadata/{metadataKey}",
module.getId(), knownKey))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(
parameterWithName("softwareModuleId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("metadataKey").description(MgmtApiModelProperties.META_DATA_KEY)),
responseFields(fieldWithPath("key").description(MgmtApiModelProperties.META_DATA_KEY),
fieldWithPath("value").description(MgmtApiModelProperties.META_DATA_VALUE),
fieldWithPath("targetVisible")
.description(MgmtApiModelProperties.SM_META_DATA_TARGET_VISIBLE))));
}
@Test
@Description(" Update a single meta data value for speficic key." + " Required Permission: "
+ SpPermission.UPDATE_REPOSITORY)
public void putMetadata() throws Exception {
// prepare and create metadata for update
final String knownKey = "knownKey";
final String knownValue = "knownValue";
final String updateValue = "valueForUpdate";
final SoftwareModule module = testdataFactory.createDistributionSet("one").findFirstModuleByType(osType).get();
softwareModuleManagement.createMetaData(
entityFactory.softwareModuleMetadata().create(module.getId()).key(knownKey).value(knownValue));
final JSONObject jsonObject = new JSONObject().put("key", knownKey).put("value", updateValue)
.put("targetVisible", true);
mockMvc.perform(
put(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/metadata/{metadataKey}",
module.getId(), knownKey).contentType(APPLICATION_JSON_HAL_UTF).content(jsonObject.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("softwareModuleId")
.description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("metadataKey").description(MgmtApiModelProperties.META_DATA_KEY)),
requestFields(requestFieldWithPath("key").description(MgmtApiModelProperties.META_DATA_KEY),
requestFieldWithPath("value").description(MgmtApiModelProperties.META_DATA_VALUE),
requestFieldWithPath("targetVisible")
.description(MgmtApiModelProperties.SM_META_DATA_TARGET_VISIBLE)),
responseFields(fieldWithPath("key").description(MgmtApiModelProperties.META_DATA_KEY),
fieldWithPath("value").description(MgmtApiModelProperties.META_DATA_VALUE),
fieldWithPath("targetVisible")
.description(MgmtApiModelProperties.SM_META_DATA_TARGET_VISIBLE))));
}
}

View File

@@ -0,0 +1,241 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.mgmt.documentation;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.restdocs.snippet.Attributes.key;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.restdocs.snippet.Snippet;
import com.fasterxml.jackson.core.JsonProcessingException;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Documentation generation for Management API for {@link TargetFilterQuery}.
*/
@Features("Spring Rest Docs Tests - TargetFilterQuery")
@Stories("TargetFilterQuery Resource")
public class TargetFilterQueriesResourceDocumentationTest extends AbstractApiRestDocumentation {
private static final String EXAMPLE_TFQ_NAME = "filter1";
private static final String EXAMPLE_TFQ_QUERY = "name==*";
@Override
@Before
public void setUp() {
resourceName = "targetfilters";
super.setUp();
}
@Test
@Description("Handles the GET request of retrieving all target filter queries within SP. Required Permission: READ_TARGET.")
public void getTargetFilterQueries() throws Exception {
createTargetFilterQueryWithDS(createDistributionSet());
mockMvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING)).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(responseFields(
fieldWithPath("size").type(JsonFieldType.NUMBER).description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_FILTER_QUERIES_LIST),
fieldWithPath("content[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("content[].name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("content[].query").description(MgmtApiModelProperties.TARGET_FILTER_QUERY),
fieldWithPath("content[].autoAssignDistributionSet")
.description(MgmtApiModelProperties.TARGET_FILTER_QUERY_AUTO_ASSIGN_DS_ID)
.type("Number"),
fieldWithPath("content[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("content[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("content[].lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath("content[].lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath("content[]._links.self").ignored())));
}
@Test
@Description("Handles the GET request of retrieving all target filter queries within SP based by parameter. Required Permission: READ_TARGET.")
public void getTargetFilterQueriesWithParameters() throws Exception {
mockMvc.perform(
get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "?limit=10&sort=name:ASC&offset=0&q=name==*1"))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(requestParameters(
parameterWithName("limit").attributes(key("type").value("query"))
.description(ApiModelPropertiesGeneric.LIMIT),
parameterWithName("sort").description(ApiModelPropertiesGeneric.SORT),
parameterWithName("offset").description(ApiModelPropertiesGeneric.OFFSET),
parameterWithName("q").description(ApiModelPropertiesGeneric.FIQL))));
}
@Test
@Description("Handles the POST request of creating a new target filter query within SP. Required Permission: CREATE_TARGET.")
public void postTargetFilterQuery() throws Exception {
final String tfqJson = createTargetFilterQueryJson(EXAMPLE_TFQ_NAME, EXAMPLE_TFQ_QUERY);
this.mockMvc
.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING)
.contentType(MediaType.APPLICATION_JSON).content(tfqJson))
.andExpect(status().isCreated()).andDo(MockMvcResultPrinter.print()).andDo(
this.document.document(
requestFields(requestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPath("query")
.description(MgmtApiModelProperties.TARGET_FILTER_QUERY)),
getResponseFieldTargetFilterQuery(false)));
}
@Test
@Description("Handles the DELETE request of deleting a single target filter query within SP. Required Permission: DELETE_TARGET.")
public void deleteTargetFilterQuery() throws Exception {
final TargetFilterQuery tfq = createTargetFilterQuery();
this.mockMvc
.perform(delete(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}",
tfq.getId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(pathParameters(
parameterWithName("targetFilterQueryId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving a single target filter query within SP. Required Permission: READ_TARGET.")
public void getTargetFilterQuery() throws Exception {
final TargetFilterQuery tfq = createTargetFilterQueryWithDS(createDistributionSet());
mockMvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}", tfq.getId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("targetFilterQueryId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
getResponseFieldTargetFilterQuery(false)));
}
@Test
@Description("Handles the PUT request of updating a target filter query within SP. Required Permission: UPDATE_TARGET.")
public void putTargetFilterQuery() throws Exception {
final TargetFilterQuery tfq = createTargetFilterQuery();
final String targetAsJson = createTargetFilterQueryJson("newFilterName", "attribute.hwRevision==2");
this.mockMvc
.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}", tfq.getId())
.contentType(MediaType.APPLICATION_JSON).content(targetAsJson))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("targetFilterQueryId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(optionalRequestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
optionalRequestFieldWithPath("query")
.description(MgmtApiModelProperties.TARGET_FILTER_QUERY)),
getResponseFieldTargetFilterQuery(false)));
}
@Test
@Description("Handles the GET request of retrieving a the auto assign distribution set of a target filter query within SP. Required Permission: READ_TARGET.")
public void getAssignDS() throws Exception {
final TargetFilterQuery tfq = createTargetFilterQueryWithDS(createDistributionSet());
mockMvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
tfq.getId())).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("targetFilterQueryId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
getResponseFieldsDistributionSet(false)));
}
@Test
@Description("Handles the POST request of setting a distribution set for auto assignment within SP. Required Permission: CREATE_TARGET.")
public void postAutoAssignDS() throws Exception {
final TargetFilterQuery tfq = createTargetFilterQuery();
final DistributionSet distributionSet = createDistributionSet();
final String filterByDistSet = "{\"id\":\"" + distributionSet.getId() + "\"}";
this.mockMvc
.perform(
post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
tfq.getId()).contentType(MediaType.APPLICATION_JSON).content(filterByDistSet))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("targetFilterQueryId")
.description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(requestFieldWithPath("id").description(MgmtApiModelProperties.DS_ID)),
getResponseFieldTargetFilterQuery(false)));
}
@Test
@Description("Handles the DELETE request of deleting the auto assign distribution set from a target filter query within SP. Required Permission: DELETE_TARGET.")
public void deleteAutoAssignDS() throws Exception {
final TargetFilterQuery tfq = createTargetFilterQueryWithDS(createDistributionSet());
this.mockMvc
.perform(delete(
MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
tfq.getId()))
.andExpect(status().isNoContent()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(pathParameters(
parameterWithName("targetFilterQueryId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
private Snippet getResponseFieldTargetFilterQuery(final boolean isArray) {
final String arrayPrefix = getArrayPrefix(isArray);
return responseFields(fieldWithPath(arrayPrefix + "id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath(arrayPrefix + "name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath(arrayPrefix + "query").description(MgmtApiModelProperties.TARGET_FILTER_QUERY),
fieldWithPath(arrayPrefix + "autoAssignDistributionSet")
.description(MgmtApiModelProperties.TARGET_FILTER_QUERY_AUTO_ASSIGN_DS_ID).type("Number"),
fieldWithPath(arrayPrefix + "createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath(arrayPrefix + "createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath(arrayPrefix + "lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath(arrayPrefix + "lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath(arrayPrefix + "_links.self").ignored(), fieldWithPath(arrayPrefix + "_links.autoAssignDS")
.description(MgmtApiModelProperties.TARGET_FILTER_QUERY_LINK_AUTO_ASSIGN_DS));
}
private String createTargetFilterQueryJson(final String name, final String query) throws JsonProcessingException {
final Map<String, Object> target = new HashMap<>();
target.put("name", name);
target.put("query", query);
return objectMapper.writeValueAsString(target);
}
private TargetFilterQuery createTargetFilterQuery() {
return targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name(EXAMPLE_TFQ_NAME).query(EXAMPLE_TFQ_QUERY));
}
private TargetFilterQuery createTargetFilterQueryWithDS(final DistributionSet distributionSet) {
final TargetFilterQuery targetFilterQuery = createTargetFilterQuery();
return targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), distributionSet.getId());
}
}

View File

@@ -0,0 +1,602 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.mgmt.documentation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.restdocs.snippet.Attributes.key;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.ActionStatusFields;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import com.fasterxml.jackson.core.JsonProcessingException;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Documentation generation for Management API for {@link Target}.
*
*/
@Features("Spring Rest Docs Tests - Target")
@Stories("Target Resource")
public class TargetResourceDocumentationTest extends AbstractApiRestDocumentation {
private final String controllerId = "137";
@Override
@Before
public void setUp() {
resourceName = "targets";
super.setUp();
}
@Test
@Description("Handles the GET request of retrieving all targets within SP. Required Permission: READ_TARGET.")
public void getTargets() throws Exception {
createTargetByGivenNameWithAttributes(controllerId, createDistributionSet());
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING)).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(responseFields(
fieldWithPath("size").type(JsonFieldType.NUMBER).description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_LIST),
fieldWithPath("content[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("content[].address").description(MgmtApiModelProperties.ADDRESS),
fieldWithPath("content[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("content[].name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("content[].description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("content[].controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("content[].updateStatus").description(MgmtApiModelProperties.UPDATE_STATUS)
.type("enum").attributes(
key("value").value("['error', 'in_sync', 'pending', 'registered', 'unknown']")),
fieldWithPath("content[].securityToken").description(MgmtApiModelProperties.SECURITY_TOKEN),
fieldWithPath("content[].installedAt").description(MgmtApiModelProperties.INSTALLED_AT),
fieldWithPath("content[].lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
fieldWithPath("content[].lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
fieldWithPath("content[].ipAddress").description(MgmtApiModelProperties.IP_ADDRESS)
.type("String"),
fieldWithPath("content[].lastControllerRequestAt")
.description(MgmtApiModelProperties.LAST_REQUEST_AT).type("Number"),
fieldWithPath("content[]._links.self").ignored())));
}
@Test
@Description("Handles the GET request of retrieving all targets within SP based by parameter. Required Permission: READ_TARGET.")
public void getTargetsWithParameters() throws Exception {
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "?limit=10&sort=name:ASC&offset=0&q=name==a"))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(getFilterRequestParamter()));
}
@Test
@Description("Handles the POST request of creating new targets within SP. The request body must always be a list of targets. Required Permission: CREATE_TARGET.")
public void postTargets() throws Exception {
final String target = createTargetJsonForPostRequest("123456", "controllerId", "test");
mockMvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING)
.contentType(MediaType.APPLICATION_JSON_UTF8).content(target)).andExpect(status().isCreated())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(requestFields(
requestFieldWithPath("[]controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
requestFieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME),
optionalRequestFieldWithPath("[]description").description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("[]address").description(MgmtApiModelProperties.ADDRESS),
optionalRequestFieldWithPath("[]securityToken")
.description(MgmtApiModelProperties.SECURITY_TOKEN)),
responseFields(fieldWithPath("[]controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME),
fieldWithPath("[]description").description(ApiModelPropertiesGeneric.DESCRPTION),
fieldWithPath("[]address").description(MgmtApiModelProperties.ADDRESS),
fieldWithPath("[]createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("[]lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY),
fieldWithPath("[]lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
fieldWithPath("[]ipAddress").description(MgmtApiModelProperties.IP_ADDRESS),
fieldWithPath("[]createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("[]updateStatus").description(MgmtApiModelProperties.UPDATE_STATUS)
.type("enum")
.attributes(key("value")
.value("['error', 'in_sync', 'pending', 'registered', 'unknown']")),
fieldWithPath("[]securityToken").description(MgmtApiModelProperties.SECURITY_TOKEN),
fieldWithPath("[]_links.self").ignored())));
}
@Test
@Description("Handles the DELETE request of deleting a single target within SP. Required Permission: DELETE_TARGET.")
public void deleteTarget() throws Exception {
final Target target = testdataFactory.createTarget(controllerId);
mockMvc.perform(
delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}", target.getControllerId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print()).andDo(this.document.document(
pathParameters(parameterWithName("controllerId").description(ApiModelPropertiesGeneric.NAME))));
}
@Test
@Description("Handles the GET request of retrieving a single target within SP. Required Permission: READ_TARGET.")
public void getTarget() throws Exception {
final Target target = createTargetByGivenNameWithAttributes(controllerId, createDistributionSet());
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}", target.getControllerId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getResponseFieldTarget(false)));
}
@Test
@Description("Handles the PUT request of updating a target within SP. Required Permission: UPDATE_TARGET.")
public void putTarget() throws Exception {
final Target target = createTargetByGivenNameWithAttributes(controllerId, createDistributionSet());
final String targetAsJson = createJsonTarget(controllerId, "newTargetName", "I've been updated");
mockMvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}", target.getControllerId())
.contentType(MediaType.APPLICATION_JSON_UTF8).content(targetAsJson)).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(requestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
requestFieldWithPath("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
requestFieldWithPath("address").description(MgmtApiModelProperties.ADDRESS),
requestFieldWithPath("securityToken")
.description(MgmtApiModelProperties.SECURITY_TOKEN)),
getResponseFieldTarget(false)));
}
@Test
@Description("Handles the GET request of retrieving the full action history of a specific target. Required Permission: READ_TARGET.")
public void getActionsFromTarget() throws Exception {
generateActionForTarget(controllerId);
mockMvc.perform(get(
MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/" + MgmtRestConstants.TARGET_V1_ACTIONS,
controllerId)).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("content[]").description(MgmtApiModelProperties.ACTION_LIST),
fieldWithPath("content[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("content[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("content[].lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
fieldWithPath("content[].lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("String"),
fieldWithPath("content[].type").description(MgmtApiModelProperties.ACTION_TYPE)
.attributes(key("value").value("['update', 'cancel']")),
fieldWithPath("content[].status")
.description(MgmtApiModelProperties.ACTION_EXECUTION_STATUS)
.attributes(key("value").value("['finished', 'pending']")),
fieldWithPath("content[]._links").description(MgmtApiModelProperties.LINK_TO_ACTION),
fieldWithPath("content[].id").description(MgmtApiModelProperties.ACTION_ID))));
}
@Test
@Description("Handles the GET request of retrieving the full action history of a specific target with maintenance window. Required Permission: READ_TARGET.")
public void getActionsFromTargetWithMaintenanceWindow() throws Exception {
generateActionForTarget(controllerId, true, false, getTestSchedule(2), getTestDuration(1), getTestTimeZone());
mockMvc.perform(get(
MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/" + MgmtRestConstants.TARGET_V1_ACTIONS,
controllerId)).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("content[]").description(MgmtApiModelProperties.ACTION_LIST),
fieldWithPath("content[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("content[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("content[].lastModifiedBy")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
fieldWithPath("content[].lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("String"),
fieldWithPath("content[].type").description(MgmtApiModelProperties.ACTION_TYPE)
.attributes(key("value").value("['update', 'cancel']")),
fieldWithPath("content[].status")
.description(MgmtApiModelProperties.ACTION_EXECUTION_STATUS)
.attributes(key("value").value("['finished', 'pending']")),
fieldWithPath("content[]._links").description(MgmtApiModelProperties.LINK_TO_ACTION),
fieldWithPath("content[].id").description(MgmtApiModelProperties.ACTION_ID),
fieldWithPath("content[].maintenanceWindow")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW),
fieldWithPath("content[].maintenanceWindow.schedule")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_SCHEDULE),
fieldWithPath("content[].maintenanceWindow.duration")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_DURATION),
fieldWithPath("content[].maintenanceWindow.timezone")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_TIMEZONE),
fieldWithPath("content[].maintenanceWindow.nextStartAt")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_NEXT_START_AT))));
}
@Test
@Description("Handles the GET request of retrieving all targets within SP based by parameter. Required Permission: READ_TARGET.")
public void getActionsFromTargetWithParameters() throws Exception {
generateActionForTarget(controllerId);
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + controllerId + "/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "?limit=10&sort=id:ASC&offset=0&q=status==pending"))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(requestParameters(
parameterWithName("limit").attributes(key("type").value("query"))
.description(ApiModelPropertiesGeneric.LIMIT),
parameterWithName("sort").description(ApiModelPropertiesGeneric.SORT),
parameterWithName("offset").description(ApiModelPropertiesGeneric.OFFSET),
parameterWithName("q").description(ApiModelPropertiesGeneric.FIQL))));
}
@Test
@Description("Cancels an active action, only active actions can be deleted. Required Permission: UPDATE_TARGET.")
public void deleteActionFromTarget() throws Exception {
final Action actions = generateActionForTarget(controllerId, false);
mockMvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}", controllerId, actions.getId()))
.andExpect(status().isNoContent()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("actionId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving all targets within SP based by parameter. Required Permission: READ_TARGET.")
public void deleteActionsFromTargetWithParameters() throws Exception {
generateActionForTarget(controllerId);
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + controllerId + "/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "?force=true")).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print()).andDo(this.document.document(
requestParameters(parameterWithName("force").description(MgmtApiModelProperties.FORCE))));
}
@Test
@Description("Handles the GET request of retrieving a specific action on a specific target. Required Permission: READ_TARGET.")
public void getActionFromTarget() throws Exception {
final Action action = generateActionForTarget(controllerId, true, true);
assertThat(deploymentManagement.findAction(action.getId()).get().getActionType())
.isEqualTo(ActionType.TIMEFORCED);
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}", controllerId, action.getId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("actionId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("id").description(MgmtApiModelProperties.ACTION_ID),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
.type("String"),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
.type("String"),
fieldWithPath("type").description(MgmtApiModelProperties.ACTION_TYPE)
.attributes(key("value").value("['update', 'cancel']")),
fieldWithPath("forceType").description(MgmtApiModelProperties.ACTION_FORCE_TYPE)
.attributes(key("value").value("['forced', 'soft', 'timeforced']")),
fieldWithPath("forceTime").description(MgmtApiModelProperties.ACTION_FORCE_TIME)
.type("String"),
fieldWithPath("status").description(MgmtApiModelProperties.ACTION_EXECUTION_STATUS)
.attributes(key("value").value("['finished', 'pending']")),
fieldWithPath("_links.self").ignored(),
fieldWithPath("_links.distributionset").description(MgmtApiModelProperties.LINK_TO_DS),
fieldWithPath("_links.status")
.description(MgmtApiModelProperties.LINKS_ACTION_STATUSES))));
}
@Test
@Description("Handles the GET request of retrieving a specific action on a specific target. Required Permission: READ_TARGET.")
public void getActionFromTargetWithMaintenanceWindow() throws Exception {
final Action action = generateActionForTarget(controllerId, true, true, getTestSchedule(2), getTestDuration(1),
getTestTimeZone());
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}", controllerId, action.getId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("actionId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("id").description(MgmtApiModelProperties.ACTION_ID),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
.type("String"),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
.type("String"),
fieldWithPath("type").description(MgmtApiModelProperties.ACTION_TYPE)
.attributes(key("value").value("['update', 'cancel']")),
fieldWithPath("forceType").description(MgmtApiModelProperties.ACTION_FORCE_TYPE)
.attributes(key("value").value("['forced', 'soft', 'timeforced']")),
fieldWithPath("forceTime").description(MgmtApiModelProperties.ACTION_FORCE_TIME)
.type("String"),
fieldWithPath("status").description(MgmtApiModelProperties.ACTION_EXECUTION_STATUS)
.attributes(key("value").value("['finished', 'pending']")),
fieldWithPath("maintenanceWindow")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW),
fieldWithPath("maintenanceWindow.schedule")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_SCHEDULE),
fieldWithPath("maintenanceWindow.duration")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_DURATION),
fieldWithPath("maintenanceWindow.timezone")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_TIMEZONE),
fieldWithPath("maintenanceWindow.nextStartAt")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_NEXT_START_AT),
fieldWithPath("_links.self").ignored(),
fieldWithPath("_links.distributionset").description(MgmtApiModelProperties.LINK_TO_DS),
fieldWithPath("_links.status")
.description(MgmtApiModelProperties.LINKS_ACTION_STATUSES))));
}
@Test
@Description("Handles the PUT request to switch an action from soft to forced. Required Permission: UPDATE_TARGET.")
public void switchActionToForced() throws Exception {
final Target target = testdataFactory.createTarget(controllerId);
final DistributionSet set = testdataFactory.createDistributionSet();
final Long actionId = deploymentManagement
.assignDistributionSet(set.getId(), ActionType.SOFT, 0, Arrays.asList(target.getControllerId()))
.getActions().get(0);
assertThat(deploymentManagement.findAction(actionId).get().getActionType()).isEqualTo(ActionType.SOFT);
final Map<String, Object> body = new HashMap<>();
body.put("forceType", "forced");
mockMvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}", controllerId, actionId)
.content(this.objectMapper.writeValueAsString(body))
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("actionId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(
requestFieldWithPath("forceType").description(MgmtApiModelProperties.ACTION_FORCED)),
responseFields(fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("id").description(MgmtApiModelProperties.ACTION_ID),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
.type("String"),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
.type("String"),
fieldWithPath("type").description(MgmtApiModelProperties.ACTION_TYPE)
.attributes(key("value").value("['update', 'cancel']")),
fieldWithPath("forceType").description(MgmtApiModelProperties.ACTION_FORCE_TYPE)
.attributes(key("value").value("['forced', 'soft', 'timeforced']")),
fieldWithPath("status").description(MgmtApiModelProperties.ACTION_EXECUTION_STATUS)
.attributes(key("value").value("['finished', 'pending']")),
fieldWithPath("_links.self").ignored(),
fieldWithPath("_links.distributionset").description(MgmtApiModelProperties.LINK_TO_DS),
fieldWithPath("_links.status")
.description(MgmtApiModelProperties.LINKS_ACTION_STATUSES))));
}
@Test
@Description("Handles the GET request of retrieving a specific action on a specific target. Required Permission: READ_TARGET.")
public void getStatusFromAction() throws Exception {
final Action action = generateActionForTarget(controllerId);
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}/" + MgmtRestConstants.TARGET_V1_ACTION_STATUS,
controllerId, action.getId())).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("actionId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("content[]").description(MgmtApiModelProperties.ACTION_STATUS_LIST),
fieldWithPath("content[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
fieldWithPath("content[].messages")
.description(MgmtApiModelProperties.ACTION_STATUS_MESSAGES).type("String"),
fieldWithPath("content[].reportedAt")
.description(MgmtApiModelProperties.ACTION_STATUS_REPORTED_AT).type("String"),
fieldWithPath("content[].type").description(MgmtApiModelProperties.ACTION_STATUS_TYPE)
.attributes(key("value").value(
"['finished', 'error', 'warning', 'pending', 'running', 'canceled', 'retrieved', 'canceling']")))));
}
@Test
@Description("Handles the GET request of retrieving all targets within SP based by parameter. Required Permission: READ_TARGET.")
public void getStatusFromActionWithParameters() throws Exception {
final Action action = generateActionForTarget(controllerId);
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + controllerId + "/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/"
+ MgmtRestConstants.TARGET_V1_ACTION_STATUS + "?limit=10&sort=id:ASC&offset=0"))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
requestParameters(parameterWithName("limit").description(ApiModelPropertiesGeneric.LIMIT),
parameterWithName("sort").description(ApiModelPropertiesGeneric.SORT),
parameterWithName("offset").description(ApiModelPropertiesGeneric.OFFSET))));
}
@Test
@Description("Handles the GET request of retrieving the assigned distribution set of an specific target. Required Permission: READ_TARGET.")
public void getAssignedDistributionSetFromAction() throws Exception {
generateActionForTarget(controllerId);
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ASSIGNED_DISTRIBUTION_SET, controllerId)).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getResponseFieldsDistributionSet(false)));
}
@Test
@Description("Handles the POST request for assigning a distribution set to a specific target. Required Permission: READ_REPOSITORY and UPDATE_TARGET.")
public void postAssignDistributionSetToTarget() throws Exception {
testdataFactory.createTarget(controllerId);
final DistributionSet set = testdataFactory.createDistributionSet("one");
final long forceTime = System.currentTimeMillis();
final String body = new JSONObject().put("id", set.getId()).put("type", "timeforced")
.put("forcetime", forceTime).put("maintenanceWindow",
getMaintenanceWindow(getTestSchedule(10), getTestDuration(10), getTestTimeZone()))
.toString();
mockMvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ASSIGNED_DISTRIBUTION_SET, controllerId).content(body)
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestParameters(parameterWithName("offline")
.description(MgmtApiModelProperties.OFFLINE_UPDATE).optional()),
requestFields(requestFieldWithPath("forcetime").description(MgmtApiModelProperties.FORCETIME),
requestFieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
requestFieldWithPath("maintenanceWindow")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW).optional(),
requestFieldWithPath("maintenanceWindow.schedule")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_SCHEDULE).optional(),
requestFieldWithPath("maintenanceWindow.duration")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_DURATION).optional(),
requestFieldWithPath("maintenanceWindow.timezone")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_TIMEZONE).optional(),
requestFieldWithPath("type").description(MgmtApiModelProperties.FORCETIME_TYPE)
.attributes(key("value").value("['soft', 'forced','timeforced']"))),
responseFields(
fieldWithPath("assigned").description(MgmtApiModelProperties.DS_NEW_ASSIGNED_TARGETS),
fieldWithPath("alreadyAssigned").type(JsonFieldType.NUMBER)
.description(MgmtApiModelProperties.DS_ALREADY_ASSIGNED_TARGETS),
fieldWithPath("total").type(JsonFieldType.NUMBER)
.description(MgmtApiModelProperties.DS_TOTAL_ASSIGNED_TARGETS))));
}
@Test
@Description("Handles the GET request of retrieving the attributes of a specific target. Reponse is a key/value list. Required Permission: READ_TARGET.")
public void getControllerAttributes() throws Exception {
// create target with attributes
final Map<String, String> knownControllerAttrs = new HashMap<>();
knownControllerAttrs.put("a", "1");
knownControllerAttrs.put("b", "2");
final Target target = testdataFactory.createTarget(controllerId);
controllerManagement.updateControllerAttributes(controllerId, knownControllerAttrs, null);
// test query target over rest resource
mockMvc.perform(
get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/attributes", target.getName()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().is2xxSuccessful())
.andExpect(jsonPath("$.a", equalTo("1"))).andExpect(jsonPath("$.b", equalTo("2")))
.andDo(this.document.document(pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving the installed distribution set of an specific target. Required Permission: READ_TARGET.")
public void getInstalledDistributionSetFromTarget() throws Exception {
final Target target = createTargetByGivenNameWithAttributes(controllerId, createDistributionSet());
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_INSTALLED_DISTRIBUTION_SET, target.getName())).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getResponseFieldsDistributionSet(false)));
}
private String createTargetJsonForPostRequest(final String controllerId, final String name,
final String description) throws JsonProcessingException {
final Map<String, Object> target = new HashMap<>();
target.put("controllerId", controllerId);
target.put("description", description);
target.put("name", name);
target.put("address", "https://192.168.0.1");
target.put("securityToken", "2345678DGGDGFTDzztgf");
return "[" + this.objectMapper.writeValueAsString(target) + "]";
}
private String createJsonTarget(final String controllerId, final String name, final String description)
throws JsonProcessingException {
final Map<String, Object> target = new HashMap<>();
target.put("controllerId", controllerId);
target.put("description", description);
target.put("name", name);
target.put("address", "https://192.168.0.1");
target.put("securityToken", "2345678DGGDGFTDzztgf");
return this.objectMapper.writeValueAsString(target);
}
private Action generateActionForTarget(final String knownControllerId) throws Exception {
return generateActionForTarget(knownControllerId, true, false, null, null, null);
}
private Action generateActionForTarget(final String knownControllerId, final boolean inSync) throws Exception {
return generateActionForTarget(knownControllerId, inSync, false, null, null, null);
}
private Action generateActionForTarget(final String knownControllerId, final boolean inSync,
final boolean timeforced) throws Exception {
return generateActionForTarget(knownControllerId, inSync, timeforced, null, null, null);
}
private Action generateActionForTarget(final String knownControllerId, final boolean inSync,
final boolean timeforced, final String maintenanceWindowSchedule, final String maintenanceWindowDuration,
final String maintenanceWindowTimeZone) throws Exception {
final PageRequest pageRequest = new PageRequest(0, 1, Direction.ASC, ActionStatusFields.ID.getFieldName());
createTargetByGivenNameWithAttributes(knownControllerId, inSync, timeforced, createDistributionSet(),
maintenanceWindowSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone);
final List<Action> actions = deploymentManagement.findActionsAll(pageRequest).getContent();
assertThat(actions).hasSize(1);
return actions.get(0);
}
}

View File

@@ -0,0 +1,307 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.mgmt.documentation;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedTargetRequestBody;
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.documentation.DocumenationResponseFieldsSnippet;
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.FieldDescriptor;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.restdocs.snippet.Snippet;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Documentation generation for Management API for {@link TargetTag}.
*
*/
@Features("Spring Rest Docs Tests - TargetTag")
@Stories("TargetTag Resource")
public class TargetTagResourceDocumentationTest extends AbstractApiRestDocumentation {
private DistributionSet distributionSet;
@Override
@Before
public void setUp() {
resourceName = "targettag";
super.setUp();
distributionSet = createDistributionSet();
}
@Test
@Description("Handles the GET request of retrieving all target tags")
public void getTargetTags() throws Exception {
createTargetTagEntitiy();
arrayPrefix = "content[].";
mockMvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING)).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(getResponseFieldTargetTag(true,
fieldWithPath("size").type(JsonFieldType.NUMBER).description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_LIST))));
}
@Test
@Description("Handles the GET request of retrieving all targets tags within SP based by parameter")
public void getTargetTagsWithParameters() throws Exception {
createTargetTagEntitiy();
mockMvc.perform(get(
MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "?limit=10&sort=name:ASC&offset=0&q=name==targetTag"))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(getFilterRequestParamter()));
}
@Test
@Description("Handles the GET request of retrieving all target tag within SP. Required Permission: READ_TARGET.")
public void getTargetTag() throws Exception {
final Long tagId = createTargetTagId();
mockMvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/{targetTagId}", tagId))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("targetTagId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getResponseFieldTargetTag(false)));
}
@Test
@Description(" Handles the POST request of creating new target tags. The request body must always be a list of tags")
public void createTargetTags() throws Exception {
final MgmtTagRequestBodyPut bodyPut = new MgmtTagRequestBodyPut();
bodyPut.setColour("red");
bodyPut.setDescription("target tag description");
bodyPut.setName("target tag");
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(Arrays.asList(bodyPut));
this.mockMvc
.perform(post(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING).content(json)
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isCreated()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(getRequestFieldsTargetTag(true), getResponseFieldTargetTag(true)));
}
@Test
@Description("Handles the PUT request of updating a single target tag.")
public void updateTagretTag() throws Exception {
final Long tagId = createTargetTagId();
final MgmtTagRequestBodyPut bodyPut = new MgmtTagRequestBodyPut();
bodyPut.setColour("red");
bodyPut.setDescription("target tag description");
bodyPut.setName("target tag");
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(bodyPut);
this.mockMvc
.perform(put(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/{targetTagId}", tagId).content(json)
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("targetTagId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getRequestFieldsTargetTag(false), getResponseFieldTargetTag(false)));
}
@Test
@Description("Handles the DELETE request for a single target tag")
public void deleteTargetTag() throws Exception {
final Long tagId = createTargetTagId();
this.mockMvc
.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/{targetTagId}", tagId)
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(pathParameters(
parameterWithName("targetTagId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving all assigned targets by the given")
public void getAssignedTargets() throws Exception {
final TargetTag tag = createTargetTagEntitiy();
final Target target = createTargetByGivenNameWithAttributes("Target1", distributionSet);
targetManagement.assignTag(Arrays.asList(target.getControllerId()), tag.getId());
arrayPrefix = "content[].";
this.mockMvc
.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING
+ MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING, tag.getId())
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("targetTagId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getResponseFieldTarget(true,
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_LIST))));
}
@Test
@Description("Handles the POST request to toggle the assignment of targets by the given tag id")
public void toggleTagAssignment() throws Exception {
final Target assignTarget = createTargetByGivenNameWithAttributes("AssignedTarget", distributionSet);
final Target unassignTarget = createTargetByGivenNameWithAttributes("UnassignedTarget", distributionSet);
final Long tagId = createTargetTagId();
final MgmtAssignedTargetRequestBody assignedTargetRequestBody1 = new MgmtAssignedTargetRequestBody();
assignedTargetRequestBody1
.setControllerId(createTargetByGivenNameWithAttributes("Target1", distributionSet).getControllerId());
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(Arrays.asList(assignedTargetRequestBody1));
this.mockMvc
.perform(post(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING
+ MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING + "/toggleTagAssignment", tagId)
.content(json).contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("targetTagId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getRequestFieldsTargetAssignment(true),
getResponseAssignmentResult(assignTarget, unassignTarget)
));
}
@Test
@Description("Handles the POST request to assign targets to the given tag id")
public void assignTargets() throws Exception {
final Long tagId = createTargetTagId();
final MgmtAssignedTargetRequestBody assignedTargetRequestBody1 = new MgmtAssignedTargetRequestBody();
assignedTargetRequestBody1
.setControllerId(createTargetByGivenNameWithAttributes("Target1", distributionSet).getControllerId());
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(Arrays.asList(assignedTargetRequestBody1));
this.mockMvc
.perform(post(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING
+ MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING, tagId).content(json)
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("targetTagId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getRequestFieldsTargetAssignment(true), getResponseFieldTarget(true)));
}
@Test
@Description("Handles the DELETE request to unassign one target from the given tag id")
public void unassignTarget() throws Exception {
final Long tagId = createTargetTagId();
final Target target = testdataFactory.createTarget();
this.mockMvc
.perform(delete(
MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING
+ MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING + "/{controllerId}",
tagId, target.getControllerId()).contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("targetTagId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
private Snippet getRequestFieldsTargetTag(final boolean isArray) {
final String arrayPrefix = getArrayPrefix(isArray);
return requestFields(requestFieldWithPath(arrayPrefix + "name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPath(arrayPrefix + "description").description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath(arrayPrefix + "colour").description(ApiModelPropertiesGeneric.COLOUR));
}
private Snippet getRequestFieldsTargetAssignment(final boolean isArray) {
final String arrayPrefix = getArrayPrefix(isArray);
return requestFields(
requestFieldWithPath(arrayPrefix + "controllerId").description(ApiModelPropertiesGeneric.ITEM_ID));
}
private Snippet getResponseFieldTargetTag(final boolean isArray) throws JsonProcessingException {
return getResponseFieldTargetTag(isArray, new FieldDescriptor[0]);
}
private Snippet getResponseFieldTargetTag(final boolean isArray, final FieldDescriptor... descriptors)
throws JsonProcessingException {
final String arrayPrefix = getArrayPrefix(isArray);
final List<FieldDescriptor> allFieldDescriptor = new ArrayList<>();
allFieldDescriptor.addAll(Arrays.asList(descriptors));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "id").description(ApiModelPropertiesGeneric.ITEM_ID));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "name").description(ApiModelPropertiesGeneric.NAME));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "description").description(ApiModelPropertiesGeneric.DESCRPTION));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "createdBy").description(ApiModelPropertiesGeneric.CREATED_BY));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "createdAt").description(ApiModelPropertiesGeneric.CREATED_AT));
allFieldDescriptor.add(
fieldWithPath(arrayPrefix + "lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY));
allFieldDescriptor.add(
fieldWithPath(arrayPrefix + "lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "colour").description(ApiModelPropertiesGeneric.COLOUR));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.self").ignored());
if (!isArray) {
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.assignedTargets")
.description(MgmtApiModelProperties.LINKS_ASSIGNED_TARGETS));
}
return new DocumenationResponseFieldsSnippet(allFieldDescriptor);
}
private Snippet getResponseAssignmentResult(final Target assignTarget, final Target unAssignTarget)
throws JsonProcessingException {
return responseFields(
fieldWithPath("assignedTargets").description(MgmtApiModelProperties.ASSIGNED_TARGETS)
.type("Array[Object]"),
fieldWithPath("unassignedTargets").description(MgmtApiModelProperties.UN_ASSIGNED_TARGETS)
.type("Array[Object]"));
}
private TargetTag createTargetTagEntitiy(final String name) {
final TargetTag updateTargetTag = targetTagManagement.create(entityFactory.tag().create().name(name));
return targetTagManagement.update(entityFactory.tag().update(updateTargetTag.getId())
.description("My name is " + name).colour("default"));
}
private TargetTag createTargetTagEntitiy() {
return createTargetTagEntitiy("targetTag");
}
private Long createTargetTagId() {
return createTargetTagEntitiy().getId();
}
}

View File

@@ -0,0 +1,177 @@
/**
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.rest.mgmt.documentation;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValueRequest;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.FieldDescriptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Documentation generation for System API for {@link TenantConfiguration}.
*/
@Features("Spring Rest Docs Tests - TenantConfiguration")
@Stories("TenantConfiguration Resource")
public class TenantResourceDocumentationTest extends AbstractApiRestDocumentation {
protected static final Map<String, String> CONFIG_ITEM_DESCRIPTIONS = new HashMap<>();
static {
CONFIG_ITEM_DESCRIPTIONS.put(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED,
"if the authentication mode 'gateway security token' is enabled.");
CONFIG_ITEM_DESCRIPTIONS.put(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY,
"the key of the gateway security token.");
CONFIG_ITEM_DESCRIPTIONS.put(TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME,
"the name of the 'authority header'.");
CONFIG_ITEM_DESCRIPTIONS.put(TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED,
"if the authentication mode 'authority header' is enabled.");
CONFIG_ITEM_DESCRIPTIONS.put(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED,
"if the authentication mode 'target security token' is enabled.");
CONFIG_ITEM_DESCRIPTIONS.put(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL,
"the period of time after the SP server will recognize a target, which is not performing pull requests anymore.");
CONFIG_ITEM_DESCRIPTIONS.put(TenantConfigurationKey.POLLING_TIME_INTERVAL,
"the time intervall between two poll requests of a target.");
CONFIG_ITEM_DESCRIPTIONS.put(TenantConfigurationKey.MIN_POLLING_TIME_INTERVAL,
"the smallest time intervallpermittet between two poll requests of a target.");
CONFIG_ITEM_DESCRIPTIONS.put(TenantConfigurationKey.MAINTENANCE_WINDOW_POLL_COUNT,
"the polling interval so that controller tries to poll at least these many times between the last "
+ "polling and before start of maintenance window. The polling interval is"
+ " bounded by configured pollingTime and minPollingTime. The polling"
+ " interval is modified as per following scheme: pollingTime(@time=t) ="
+ " (maintenanceWindowStartTime - t)/maintenanceWindowPollCount.");
CONFIG_ITEM_DESCRIPTIONS.put(TenantConfigurationKey.ANONYMOUS_DOWNLOAD_MODE_ENABLED,
"if the anonymous download mode is enabled.");
CONFIG_ITEM_DESCRIPTIONS.put(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED,
"if autoclose running actions with new Distribution Set assignment is enabled.");
}
@Autowired
protected TenantConfigurationProperties tenantConfigurationProperties;
@Override
@Before
public void setUp() {
resourceName = "tenant";
super.setUp();
}
@Test
@Description("Handles GET request for receiving all tenant specific configurations. Required Permission: "
+ SpPermission.TENANT_CONFIGURATION)
public void getTenantConfigrations() throws Exception {
mockMvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/")).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(responseFields(getTenantConfigurationValuesKeyResponseFields())));
}
@Test
@Description("Handles GET request for receiving a tenant specific configuration. Required Permission: "
+ SpPermission.TENANT_CONFIGURATION)
public void getTenantConfigration() throws Exception {
mockMvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}/",
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY)).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("keyName").description(MgmtApiModelProperties.CONFIG_PARAM)),
responseFields(getTenantConfigurationValueResponseField())));
}
@Test
@Description("Handles PUT request for settings values in tenant specific configuration. Required Permission: "
+ SpPermission.TENANT_CONFIGURATION)
public void putTenantConfigration() throws Exception {
final MgmtSystemTenantConfigurationValueRequest bodyPut = new MgmtSystemTenantConfigurationValueRequest();
bodyPut.setValue("exampleToken");
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(bodyPut);
mockMvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}/",
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY).content(json)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("keyName").description(MgmtApiModelProperties.CONFIG_PARAM)),
requestFields(requestFieldWithPath("value").description(MgmtApiModelProperties.CONFIG_VALUE)),
responseFields(getTenantConfigurationValueResponseField())));
}
@Test
@Description("Handles DELETE request deleting a tenant specific configuration. Required Permission: "
+ SpPermission.TENANT_CONFIGURATION)
public void deleteTenantConfigration() throws Exception {
mockMvc.perform(delete(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}/",
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY)).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print()).andDo(this.document.document(
pathParameters(parameterWithName("keyName").description(MgmtApiModelProperties.CONFIG_PARAM))));
}
private FieldDescriptor[] getTenantConfigurationValuesKeyResponseFields() {
final List<FieldDescriptor> fields = new ArrayList<>();
for (final TenantConfigurationKey key : tenantConfigurationProperties.getConfigurationKeys()) {
fields.add(fieldWithPath("['" + key.getKeyName() + "']").type(key.getDataType().getSimpleName())
.description(getTenantConfigurationKeyDescription(key)));
}
return fields.toArray(new FieldDescriptor[fields.size()]);
}
private FieldDescriptor[] getTenantConfigurationValueResponseField() {
return new FieldDescriptor[] { fieldWithPath("value").description(MgmtApiModelProperties.CONFIG_VALUE),
fieldWithPath("global").description(MgmtApiModelProperties.CONFIG_GLOBAL),
fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY).type("Number").optional(),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT).type("String").optional(),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number")
.optional(),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String")
.optional(),
fieldWithPath("_links.self").ignored() };
}
private String getTenantConfigurationKeyDescription(final TenantConfigurationKey key) {
if (!CONFIG_ITEM_DESCRIPTIONS.containsKey(key.getKeyName())) {
throw new IllegalArgumentException("Description for key " + key.getKeyName() + " is missing.");
}
return "The configuration key '" + key.getKeyName() + "' defines "
+ CONFIG_ITEM_DESCRIPTIONS.get(key.getKeyName());
}
}

View File

@@ -0,0 +1,9 @@
|===
|Parameter|Description
{{#parameters}}
|{{name}}
|{{description}}
{{/parameters}}
|===

View File

@@ -0,0 +1,12 @@
|===
|Path|Type|Description|Allowed Values|Mandatory
{{#fields}}
|{{path}}
|{{type}}
|{{description}}
|{{value}}
|{{mandatory}}
{{/fields}}
|===

View File

@@ -0,0 +1,11 @@
|===
|Path|Type|Description|Allowed Values
{{#fields}}
|{{path}}
|{{type}}
|{{description}}
|{{value}}
{{/fields}}
|===

View File

@@ -0,0 +1,37 @@
#
# Copyright (c) 2018 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
#
hawkbit.controller.pollingTime=12:00:00
hawkbit.controller.pollingOverdueTime=23:59:59
## Configuration for building download URLs - START
# HTTP
hawkbit.artifact.url.protocols.download-http.rel=download-http
hawkbit.artifact.url.protocols.download-http.protocol=http
hawkbit.artifact.url.protocols.download-http.hostname=link-to-cdn.com
hawkbit.artifact.url.protocols.download-http.supports=DMF,DDI
hawkbit.artifact.url.protocols.download-http.ref={protocol}://{hostname}/api/v1/{tenant}/download/controller/{controllerId}/softwaremodules/{softwareModuleId}/filename/{artifactFileName}
hawkbit.artifact.url.protocols.md5sum-http.rel=md5sum-http
hawkbit.artifact.url.protocols.md5sum-http.protocol=${hawkbit.artifact.url.protocols.download-http.protocol}
hawkbit.artifact.url.protocols.md5sum-http.hostname=${hawkbit.artifact.url.protocols.download-http.hostname}
hawkbit.artifact.url.protocols.md5sum-http.supports=DDI
hawkbit.artifact.url.protocols.md5sum-http.ref=${hawkbit.artifact.url.protocols.download-http.ref}.MD5SUM
# HTTPS
hawkbit.artifact.url.protocols.download.rel=download
hawkbit.artifact.url.protocols.download.protocol=https
hawkbit.artifact.url.protocols.download.hostname=link-to-cdn.com
hawkbit.artifact.url.protocols.download.supports=DMF,DDI
hawkbit.artifact.url.protocols.download.ref={protocol}://{hostname}/api/v1/{tenant}/download/controller/{controllerId}/softwaremodules/{softwareModuleId}/filename/{artifactFileName}
hawkbit.artifact.url.protocols.md5sum.rel=md5sum
hawkbit.artifact.url.protocols.md5sum.protocol=${hawkbit.artifact.url.protocols.download.protocol}
hawkbit.artifact.url.protocols.md5sum.hostname=${hawkbit.artifact.url.protocols.download.hostname}
hawkbit.artifact.url.protocols.md5sum.supports=DDI
hawkbit.artifact.url.protocols.md5sum.ref=${hawkbit.artifact.url.protocols.download.ref}.MD5SUM
## Configuration for building download URLs - END