Code refactoring of hawkbit-ddi-resource (#2053)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-11-16 20:17:27 +02:00
committed by GitHub
parent ca2c50ffa5
commit c90e3384ef
12 changed files with 979 additions and 855 deletions

View File

@@ -13,6 +13,8 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.eclipse.hawkbit.artifact.repository.urlhandler.ApiType;
import org.eclipse.hawkbit.artifact.repository.urlhandler.ArtifactUrlHandler;
import org.eclipse.hawkbit.artifact.repository.urlhandler.URLPlaceholder;
@@ -44,14 +46,11 @@ import org.springframework.util.CollectionUtils;
/**
* Utility class for the DDI API.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class DataConversionHelper {
// utility class, private constructor.
private DataConversionHelper() {
}
public static DdiConfirmationBase createConfirmationBase(final Target target, final Action activeAction,
public static DdiConfirmationBase createConfirmationBase(
final Target target, final Action activeAction,
final DdiAutoConfirmationState autoConfirmationState, final TenantAware tenantAware) {
final String controllerId = target.getControllerId();
final DdiConfirmationBase confirmationBase = new DdiConfirmationBase(autoConfirmationState);
@@ -77,7 +76,8 @@ public final class DataConversionHelper {
return confirmationBase;
}
public static DdiControllerBase fromTarget(final Target target, final Action installedAction,
public static DdiControllerBase fromTarget(
final Target target, final Action installedAction,
final Action activeAction, final String defaultControllerPollTime, final TenantAware tenantAware) {
final DdiControllerBase result = new DdiControllerBase(
new DdiConfig(new DdiPolling(defaultControllerPollTime)));
@@ -97,14 +97,13 @@ public final class DataConversionHelper {
activeAction.getId()))
.withRel(DdiRestConstants.CANCEL_ACTION).expand());
} else {
// we need to add the hashcode here of the actionWithStatus
// because the action might
// have changed from 'soft' to 'forced' type and we need to
// change the payload of the
// we need to add the hashcode here of the actionWithStatus because the action might
// have changed from 'soft' to 'forced' type, and we need to change the payload of the
// response because of eTags.
result.add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder
.methodOn(DdiRootController.class, tenantAware.getCurrentTenant())
.getControllerDeploymentBaseAction(tenantAware.getCurrentTenant(), target.getControllerId(),
.getControllerDeploymentBaseAction(
tenantAware.getCurrentTenant(), target.getControllerId(),
activeAction.getId(), calculateEtag(activeAction), null))
.withRel(DdiRestConstants.DEPLOYMENT_BASE_ACTION).expand());
}
@@ -121,7 +120,8 @@ public final class DataConversionHelper {
if (target.isRequestControllerAttributes()) {
result.add(WebMvcLinkBuilder
.linkTo(WebMvcLinkBuilder.methodOn(DdiRootController.class, tenantAware.getCurrentTenant())
.linkTo(WebMvcLinkBuilder
.methodOn(DdiRootController.class, tenantAware.getCurrentTenant())
.putConfigData(null, tenantAware.getCurrentTenant(), target.getControllerId()))
.withRel(DdiRestConstants.CONFIG_DATA_ACTION).expand());
}
@@ -129,10 +129,10 @@ public final class DataConversionHelper {
return result;
}
static List<DdiChunk> createChunks(final Target target, final Action uAction,
static List<DdiChunk> createChunks(
final Target target, final Action uAction,
final ArtifactUrlHandler artifactUrlHandler, final SystemManagement systemManagement,
final HttpRequest request, final ControllerManagement controllerManagement) {
final Map<Long, List<SoftwareModuleMetadata>> metadata = controllerManagement
.findTargetVisibleMetaDataBySoftwareModuleId(uAction.getDistributionSet().getModules().stream()
.map(SoftwareModule::getId).collect(Collectors.toList()));
@@ -156,7 +156,8 @@ public final class DataConversionHelper {
}
private static List<DdiMetadata> mapMetadata(final List<SoftwareModuleMetadata> metadata) {
return CollectionUtils.isEmpty(metadata) ? null
return CollectionUtils.isEmpty(metadata)
? null
: metadata.stream().map(md -> new DdiMetadata(md.getKey(), md.getValue())).collect(Collectors.toList());
}
@@ -167,11 +168,11 @@ public final class DataConversionHelper {
if ("runtime".equals(key)) {
return "jvm";
}
return key;
}
private static DdiArtifact createArtifact(final Target target, final ArtifactUrlHandler artifactUrlHandler,
private static DdiArtifact createArtifact(
final Target target, final ArtifactUrlHandler artifactUrlHandler,
final Artifact artifact, final SystemManagement systemManagement, final HttpRequest request) {
final DdiArtifact file = new DdiArtifact();
file.setHashes(new DdiArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash(), artifact.getSha256Hash()));
@@ -187,13 +188,11 @@ public final class DataConversionHelper {
.forEach(entry -> file.add(Link.of(entry.getRef()).withRel(entry.getRel()).expand()));
return file;
}
/**
* Calculates an etag for the given {@link Action} based on the entities
* hashcode and the {@link Action#isHitAutoForceTime(long)} to reflect a
* force switch.
* Calculates an etag for the given {@link Action} based on the entities hashcode and the {@link Action#isHitAutoForceTime(long)}
* to reflect a force switch.
*
* @param action to calculate the etag for
* @return the etag
@@ -207,5 +206,4 @@ public final class DataConversionHelper {
result = prime * result + offsetPrime;
return result;
}
}
}

View File

@@ -23,7 +23,5 @@ import org.springframework.stereotype.Controller;
*/
@Configuration
@ComponentScan
@Import({ RestConfiguration.class, OpenApiConfiguration.class })
public class DdiApiConfiguration {
}
@Import({ RestConfiguration.class, OpenApiConfiguration.class, DdiOpenApiConfiguration.class })
public class DdiApiConfiguration {}

View File

@@ -91,9 +91,9 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
/**
* The {@link DdiRootController} of the hawkBit server DDI API that is queried
* by the hawkBit controller in order to pull {@link Action}s that have to be
* fulfilled and report status updates concerning the {@link Action} processing.
* The {@link DdiRootController} of the hawkBit server DDI API that is queried by the hawkBit
* controller in order to pull {@link Action}s that have to be fulfilled and report status updates concerning
* the {@link Action} processing.
*
* Transactional (read-write) as all queries at least update the last poll time.
*/
@@ -139,7 +139,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
private EntityFactory entityFactory;
@Override
public ResponseEntity<List<DdiArtifact>> getSoftwareModulesArtifacts(@PathVariable("tenant") final String tenant,
public ResponseEntity<List<DdiArtifact>> getSoftwareModulesArtifacts(
@PathVariable("tenant") final String tenant,
@PathVariable("controllerId") final String controllerId,
@PathVariable("softwareModuleId") final Long softwareModuleId) {
log.debug("getSoftwareModulesArtifacts({})", controllerId);
@@ -156,7 +157,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
@Override
public ResponseEntity<DdiControllerBase> getControllerBase(@PathVariable("tenant") final String tenant,
public ResponseEntity<DdiControllerBase> getControllerBase(
@PathVariable("tenant") final String tenant,
@PathVariable("controllerId") final String controllerId) {
log.debug("getControllerBase({})", controllerId);
@@ -170,9 +172,10 @@ public class DdiRootController implements DdiRootControllerRestApi {
// activeAction
return new ResponseEntity<>(DataConversionHelper.fromTarget(target, installedAction, activeAction,
activeAction == null ? controllerManagement.getPollingTime()
: controllerManagement.getPollingTimeForAction(activeAction.getId()),
tenantAware), HttpStatus.OK);
activeAction == null
? controllerManagement.getPollingTime()
: controllerManagement.getPollingTimeForAction(activeAction.getId()), tenantAware),
HttpStatus.OK);
}
@Override
@@ -200,11 +203,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
if (ifMatch != null && !HttpUtil.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) {
result = new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED);
} else {
final ActionStatus action = checkAndLogDownload(RequestResponseContextHolder.getHttpServletRequest(),
target, module.getId());
final ActionStatus action = checkAndLogDownload(RequestResponseContextHolder.getHttpServletRequest(), target, module.getId());
final Long statusId = action.getId();
result = FileStreamingUtil.writeFileResponse(file, artifact.getFilename(), artifact.getCreatedAt(),
RequestResponseContextHolder.getHttpServletResponse(),
RequestResponseContextHolder.getHttpServletRequest(),
@@ -218,11 +218,11 @@ public class DdiRootController implements DdiRootControllerRestApi {
return result;
}
@Override
// Exception squid:S3655 - Optional access is checked in checkModule
// subroutine
// Exception squid:S3655 - Optional access is checked in checkModule subroutine
@SuppressWarnings("squid:S3655")
public ResponseEntity<Void> downloadArtifactMd5(@PathVariable("tenant") final String tenant,
@Override
public ResponseEntity<Void> downloadArtifactMd5(
@PathVariable("tenant") final String tenant,
@PathVariable("controllerId") final String controllerId,
@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("fileName") final String fileName) {
@@ -249,12 +249,12 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
return ResponseEntity.ok().build();
}
@Override
public ResponseEntity<DdiDeploymentBase> getControllerDeploymentBaseAction(
@PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId,
@PathVariable("tenant") final String tenant,
@PathVariable("controllerId") final String controllerId,
@PathVariable("actionId") final Long actionId,
@RequestParam(value = "c", required = false, defaultValue = "-1") final int resource,
@RequestParam(value = "actionHistory", defaultValue = DdiRestConstants.NO_ACTION_HISTORY) final Integer actionHistoryMessageCount) {
@@ -266,13 +266,11 @@ public class DdiRootController implements DdiRootControllerRestApi {
checkAndCancelExpiredAction(action);
if (!action.isCancelingOrCanceled() && !action.isWaitingConfirmation()) {
final DdiDeploymentBase base = generateDdiDeploymentBase(target, action, actionHistoryMessageCount);
log.debug("Found an active UpdateAction for target {}. returning deployment: {}", controllerId, base);
controllerManagement.registerRetrieved(action.getId(), RepositoryConstants.SERVER_MESSAGE_PREFIX
+ "Target retrieved update action and should start now the download.");
controllerManagement.registerRetrieved(action.getId(), RepositoryConstants.SERVER_MESSAGE_PREFIX +
"Target retrieved update action and should start now the download.");
return new ResponseEntity<>(base, HttpStatus.OK);
}
@@ -281,8 +279,10 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
@Override
public ResponseEntity<Void> postDeploymentBaseActionFeedback(@Valid @RequestBody final DdiActionFeedback feedback,
@PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId,
public ResponseEntity<Void> postDeploymentBaseActionFeedback(
@Valid @RequestBody final DdiActionFeedback feedback,
@PathVariable("tenant") final String tenant,
@PathVariable("controllerId") final String controllerId,
@PathVariable("actionId") @NotNull final Long actionId) {
log.debug("postDeploymentBaseActionFeedback for target [{},{}]: {}", controllerId, actionId, feedback);
@@ -294,8 +294,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
if (!action.isActive()) {
log.warn("Updating action {} with feedback {} not possible since action not active anymore.",
action.getId(), feedback.getStatus());
log.warn("Updating action {} with feedback {} not possible since action not active anymore.", action.getId(), feedback.getStatus());
return new ResponseEntity<>(HttpStatus.GONE);
}
@@ -305,9 +304,10 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
@Override
public ResponseEntity<Void> putConfigData(@Valid @RequestBody final DdiConfigData configData,
@PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId) {
public ResponseEntity<Void> putConfigData(
@Valid @RequestBody final DdiConfigData configData,
@PathVariable("tenant") final String tenant,
@PathVariable("controllerId") final String controllerId) {
controllerManagement.updateControllerAttributes(controllerId, configData.getData(), getUpdateMode(configData));
return ResponseEntity.ok().build();
}
@@ -322,13 +322,11 @@ public class DdiRootController implements DdiRootControllerRestApi {
final Action action = findActionForTarget(actionId, target);
if (action.isCancelingOrCanceled()) {
final DdiCancel cancel = new DdiCancel(String.valueOf(action.getId()),
new DdiCancelActionToStop(String.valueOf(action.getId())));
final DdiCancel cancel = new DdiCancel(String.valueOf(action.getId()), new DdiCancelActionToStop(String.valueOf(action.getId())));
log.debug("Found an active CancelAction for target {}. returning cancel: {}", controllerId, cancel);
controllerManagement.registerRetrieved(action.getId(), RepositoryConstants.SERVER_MESSAGE_PREFIX
+ "Target retrieved cancel action and should start now the cancellation.");
controllerManagement.registerRetrieved(action.getId(), RepositoryConstants.SERVER_MESSAGE_PREFIX +
"Target retrieved cancel action and should start now the cancellation.");
return new ResponseEntity<>(cancel, HttpStatus.OK);
}
@@ -337,7 +335,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
@Override
public ResponseEntity<Void> postCancelActionFeedback(@Valid @RequestBody final DdiActionFeedback feedback,
public ResponseEntity<Void> postCancelActionFeedback(
@Valid @RequestBody final DdiActionFeedback feedback,
@PathVariable("tenant") final String tenant,
@PathVariable("controllerId") @NotEmpty final String controllerId,
@PathVariable("actionId") @NotNull final Long actionId) {
@@ -352,7 +351,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
@Override
public ResponseEntity<DdiDeploymentBase> getControllerInstalledAction(@PathVariable("tenant") final String tenant,
public ResponseEntity<DdiDeploymentBase> getControllerInstalledAction(
@PathVariable("tenant") final String tenant,
@PathVariable("controllerId") final String controllerId, @PathVariable("actionId") final Long actionId,
@RequestParam(value = "actionHistory", defaultValue = DdiRestConstants.NO_ACTION_HISTORY) final Integer actionHistoryMessageCount) {
log.debug("getControllerInstalledAction({})", controllerId);
@@ -380,14 +380,15 @@ public class DdiRootController implements DdiRootControllerRestApi {
final DdiAutoConfirmationState autoConfirmationState = getAutoConfirmationState(controllerId);
final DdiConfirmationBase confirmationBase = DataConversionHelper.createConfirmationBase(target, activeAction,
autoConfirmationState, tenantAware);
final DdiConfirmationBase confirmationBase = DataConversionHelper.createConfirmationBase(
target, activeAction, autoConfirmationState, tenantAware);
return new ResponseEntity<>(confirmationBase, HttpStatus.OK);
}
@Override
public ResponseEntity<DdiConfirmationBaseAction> getConfirmationBaseAction(
@PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId,
@PathVariable("tenant") final String tenant,
@PathVariable("controllerId") final String controllerId,
@PathVariable("actionId") final Long actionId,
@RequestParam(value = "c", required = false, defaultValue = "-1") final int resource,
@RequestParam(value = "actionHistory", defaultValue = DdiRestConstants.NO_ACTION_HISTORY) final Integer actionHistoryMessageCount) {
@@ -399,10 +400,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
checkAndCancelExpiredAction(action);
if (!action.isCancelingOrCanceled() && action.isWaitingConfirmation()) {
final DdiConfirmationBaseAction base = generateDdiConfirmationBase(target, action,
actionHistoryMessageCount);
final DdiConfirmationBaseAction base = generateDdiConfirmationBase(target, action, actionHistoryMessageCount);
log.debug("Found an active UpdateAction for target {}. Returning confirmation: {}", controllerId, base);
return new ResponseEntity<>(base, HttpStatus.OK);
@@ -413,17 +411,15 @@ public class DdiRootController implements DdiRootControllerRestApi {
@Override
public ResponseEntity<Void> postConfirmationActionFeedback(
@Valid @RequestBody final DdiConfirmationFeedback feedback, @PathVariable("tenant") final String tenant,
@Valid @RequestBody final DdiConfirmationFeedback feedback,
@PathVariable("tenant") final String tenant,
@PathVariable("controllerId") final String controllerId,
@PathVariable("actionId") @NotNull final Long actionId) {
log.debug("provideConfirmationActionFeedback with feedback [controllerId={}, actionId={}]: {}", controllerId,
actionId, feedback);
log.debug("provideConfirmationActionFeedback with feedback [controllerId={}, actionId={}]: {}", controllerId, actionId, feedback);
final Target target = findTarget(controllerId);
final Action action = findActionForTarget(actionId, target);
try {
switch (feedback.getConfirmation()) {
case CONFIRMED:
log.info("Controller confirmed the action (actionId: {}, controllerId: {}) as we got {} report.",
@@ -452,8 +448,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
@Override
public ResponseEntity<Void> activateAutoConfirmation(final String tenant, final String controllerId,
final DdiActivateAutoConfirmation body) {
public ResponseEntity<Void> activateAutoConfirmation(
final String tenant, final String controllerId, final DdiActivateAutoConfirmation body) {
final String initiator = body == null ? null : body.getInitiator();
final String remark = body == null ? FALLBACK_REMARK : body.getRemark();
log.debug("Activate auto-confirmation request for device '{}' with payload: [initiator='{}' | remark='{}'",
@@ -470,8 +466,10 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
@Override
public ResponseEntity<Void> setAsssignedOfflineVersion(@Valid @RequestBody DdiAssignedVersion ddiAssignedVersion,
@PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId) {
public ResponseEntity<Void> setAsssignedOfflineVersion(
@Valid @RequestBody DdiAssignedVersion ddiAssignedVersion,
@PathVariable("tenant") final String tenant,
@PathVariable("controllerId") final String controllerId) {
boolean updated = controllerManagement.updateOfflineAssignedVersion(controllerId,
ddiAssignedVersion.getName(), ddiAssignedVersion.getVersion());
if (updated) {
@@ -514,29 +512,31 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
}
private static ActionStatusCreate generateActionCancelStatus(final DdiActionFeedback feedback, final Target target,
final Long actionId, final EntityFactory entityFactory) {
private static ActionStatusCreate generateActionCancelStatus(
final DdiActionFeedback feedback, final Target target, final Long actionId, final EntityFactory entityFactory) {
final ActionStatusCreate actionStatusCreate = entityFactory.actionStatus().create(actionId);
final List<String> messages = new ArrayList<>();
final Status status;
switch (feedback.getStatus().getExecution()) {
case CANCELED:
case CANCELED: {
status = handleCaseCancelCanceled(feedback, target, actionId, messages);
break;
case REJECTED:
}
case REJECTED: {
log.info("Target rejected the cancellation request (actionId: {}, controllerId: {}).", actionId,
target.getControllerId());
status = Status.CANCEL_REJECTED;
messages.add(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target rejected the cancellation request.");
break;
case CLOSED:
}
case CLOSED: {
status = handleCancelClosedCase(feedback, messages);
break;
default:
}
default: {
status = Status.RUNNING;
break;
}
}
if (feedback.getStatus().getDetails() != null) {
@@ -550,7 +550,6 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
return actionStatusCreate.status(status).messages(messages);
}
private static Status handleCancelClosedCase(final DdiActionFeedback feedback, final List<String> messages) {
@@ -565,15 +564,15 @@ public class DdiRootController implements DdiRootControllerRestApi {
return status;
}
private static Status handleCaseCancelCanceled(final DdiActionFeedback feedback, final Target target,
final Long actionId, final List<String> messages) {
private static Status handleCaseCancelCanceled(
final DdiActionFeedback feedback, final Target target, final Long actionId, final List<String> messages) {
final Status status;
log.error(
"Target reported cancel for a cancel which is not supported by the server (actionId: {}, controllerId: {}) as we got {} report.",
actionId, target.getControllerId(), feedback.getStatus().getExecution());
status = Status.WARNING;
messages.add(RepositoryConstants.SERVER_MESSAGE_PREFIX
+ "Target reported cancel for a cancel which is not supported by the server.");
messages.add(RepositoryConstants.SERVER_MESSAGE_PREFIX +
"Target reported cancel for a cancel which is not supported by the server.");
return status;
}
@@ -596,8 +595,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
final String message;
if (range != null) {
message = RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads range " + range + " of: "
+ request.getRequestURI();
message = RepositoryConstants.SERVER_MESSAGE_PREFIX +
"Target downloads range " + range + " of: " + request.getRequestURI();
} else {
message = RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads " + request.getRequestURI();
}
@@ -606,11 +605,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
entityFactory.actionStatus().create(action.getId()).status(Status.DOWNLOAD).message(message));
}
private ActionStatusCreate generateUpdateStatus(final DdiActionFeedback feedback, final String controllerId,
final Long actionId) {
private ActionStatusCreate generateUpdateStatus(final DdiActionFeedback feedback, final String controllerId, final Long actionId) {
final ActionStatusCreate actionStatusCreate = entityFactory.actionStatus().create(actionId);
final List<String> messages = new ArrayList<>();
if (!CollectionUtils.isEmpty(feedback.getStatus().getDetails())) {
@@ -625,43 +621,49 @@ public class DdiRootController implements DdiRootControllerRestApi {
final Status status;
switch (feedback.getStatus().getExecution()) {
case CANCELED:
case CANCELED: {
log.debug("Controller confirmed cancel (actionId: {}, controllerId: {}) as we got {} report.", actionId,
controllerId, feedback.getStatus().getExecution());
status = Status.CANCELED;
addMessageIfEmpty("Target confirmed cancellation.", messages);
break;
case REJECTED:
}
case REJECTED: {
log.info("Controller reported internal error (actionId: {}, controllerId: {}) as we got {} report.",
actionId, controllerId, feedback.getStatus().getExecution());
status = Status.WARNING;
addMessageIfEmpty("Target REJECTED update", messages);
break;
case CLOSED:
}
case CLOSED: {
status = handleClosedCase(feedback, controllerId, actionId, messages);
break;
case DOWNLOAD:
}
case DOWNLOAD: {
log.debug("Controller confirmed status of download (actionId: {}, controllerId: {}) as we got {} report.",
actionId, controllerId, feedback.getStatus().getExecution());
status = Status.DOWNLOAD;
addMessageIfEmpty("Target confirmed download start", messages);
break;
case DOWNLOADED:
}
case DOWNLOADED: {
log.debug("Controller confirmed download (actionId: {}, controllerId: {}) as we got {} report.", actionId,
controllerId, feedback.getStatus().getExecution());
status = Status.DOWNLOADED;
addMessageIfEmpty("Target confirmed download finished", messages);
break;
default:
}
default: {
status = handleDefaultCase(feedback, controllerId, actionId, messages);
break;
}
}
return actionStatusCreate.status(status).messages(messages);
}
private Status handleDefaultCase(final DdiActionFeedback feedback, final String controllerId, final Long actionId,
final List<String> messages) {
private Status handleDefaultCase(
final DdiActionFeedback feedback, final String controllerId, final Long actionId, final List<String> messages) {
final Status status;
log.debug("Controller reported intermediate status (actionId: {}, controllerId: {}) as we got {} report.",
actionId, controllerId, feedback.getStatus().getExecution());
@@ -670,8 +672,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
return status;
}
private Status handleClosedCase(final DdiActionFeedback feedback, final String controllerId, final Long actionId,
final List<String> messages) {
private Status handleClosedCase(
final DdiActionFeedback feedback, final String controllerId, final Long actionId, final List<String> messages) {
final Status status;
log.debug("Controller reported closed (actionId: {}, controllerId: {}) as we got {} report.", actionId,
controllerId, feedback.getStatus().getExecution());
@@ -706,8 +708,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
/**
* If the action has a maintenance schedule defined but is no longer valid,
* cancel the action.
* If the action has a maintenance schedule defined but is no longer valid, cancel the action.
*
* @param action is the {@link Action} to check.
*/
@@ -721,22 +722,21 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
}
private DdiDeploymentBase generateDdiDeploymentBase(final Target target, final Action action,
final Integer actionHistoryMessageCount) {
private DdiDeploymentBase generateDdiDeploymentBase(final Target target, final Action action, final Integer actionHistoryMessageCount) {
final DdiActionHistory actionHistory = generateDdiActionHistory(action, actionHistoryMessageCount).orElse(null);
final DdiDeployment ddiDeployment = generateDdiDeployment(target, action);
return new DdiDeploymentBase(Long.toString(action.getId()), ddiDeployment, actionHistory);
}
private DdiConfirmationBaseAction generateDdiConfirmationBase(final Target target, final Action action,
final Integer actionHistoryMessageCount) {
private DdiConfirmationBaseAction generateDdiConfirmationBase(final Target target, final Action action, final Integer actionHistoryMessageCount) {
final DdiActionHistory actionHistory = generateDdiActionHistory(action, actionHistoryMessageCount).orElse(null);
final DdiDeployment ddiDeployment = generateDdiDeployment(target, action);
return new DdiConfirmationBaseAction(Long.toString(action.getId()), ddiDeployment, actionHistory);
}
private DdiDeployment generateDdiDeployment(final Target target, final Action action) {
final List<DdiChunk> chunks = DataConversionHelper.createChunks(target, action, artifactUrlHandler,
final List<DdiChunk> chunks = DataConversionHelper.createChunks(
target, action, artifactUrlHandler,
systemManagement, new ServletServerHttpRequest(RequestResponseContextHolder.getHttpServletRequest()),
controllerManagement);
final HandlingType downloadType = calculateDownloadType(action);
@@ -745,12 +745,13 @@ public class DdiRootController implements DdiRootControllerRestApi {
return new DdiDeployment(downloadType, updateType, chunks, maintenanceWindow);
}
private Optional<DdiActionHistory> generateDdiActionHistory(final Action action,
final Integer actionHistoryMessageCount) {
private Optional<DdiActionHistory> generateDdiActionHistory(final Action action, final Integer actionHistoryMessageCount) {
final List<String> actionHistoryMsgs = controllerManagement.getActionHistoryMessages(action.getId(),
actionHistoryMessageCount == null ? Integer.parseInt(DdiRestConstants.NO_ACTION_HISTORY)
actionHistoryMessageCount == null
? Integer.parseInt(DdiRestConstants.NO_ACTION_HISTORY)
: actionHistoryMessageCount);
return actionHistoryMsgs.isEmpty() ? Optional.empty()
return actionHistoryMsgs.isEmpty()
? Optional.empty()
: Optional.of(new DdiActionHistory(action.getStatus().name(), actionHistoryMsgs));
}
@@ -779,11 +780,9 @@ public class DdiRootController implements DdiRootControllerRestApi {
* @param response the response
* @param md5Hash of the artifact
* @param filename as provided by the client
* @return the response
* @throws IOException cannot write output stream
*/
private static void writeMD5FileResponse(
final HttpServletResponse response, final String md5Hash, final String filename) throws IOException {
private static void writeMD5FileResponse(final HttpServletResponse response, final String md5Hash, final String filename) throws IOException {
if (md5Hash == null) {
throw new IllegalArgumentException("MD5 hash must not be null");
}

View File

@@ -23,6 +23,7 @@ import java.io.StringWriter;
import java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
@@ -57,8 +58,8 @@ import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@ContextConfiguration(classes = { DdiApiConfiguration.class, RestConfiguration.class,
RepositoryApplicationConfiguration.class, TestConfiguration.class })
@ContextConfiguration(
classes = { DdiApiConfiguration.class, RestConfiguration.class, RepositoryApplicationConfiguration.class, TestConfiguration.class })
@Import(TestChannelBinderConfiguration.class)
@TestPropertySource(locations = "classpath:/ddi-test.properties")
public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrationTest {
@@ -67,8 +68,7 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
protected static final String HTTP_LOCALHOST = String.format("http://localhost:%s/", HTTP_PORT);
protected static final String CONTROLLER_BASE = "/{tenant}/controller/v1/{controllerId}";
protected static final String SOFTWARE_MODULE_ARTIFACTS = CONTROLLER_BASE
+ "/softwaremodules/{softwareModuleId}/artifacts";
protected static final String SOFTWARE_MODULE_ARTIFACTS = CONTROLLER_BASE + "/softwaremodules/{softwareModuleId}/artifacts";
protected static final String DEPLOYMENT_BASE = CONTROLLER_BASE + "/deploymentBase/{actionId}";
protected static final String DEPLOYMENT_FEEDBACK = DEPLOYMENT_BASE + "/feedback";
protected static final String CANCEL_ACTION = CONTROLLER_BASE + "/cancelAction/{actionId}";
@@ -83,7 +83,8 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
protected static final String CONFIRMATION_FEEDBACK = CONFIRMATION_BASE_ACTION + "/feedback";
protected static final int ARTIFACT_SIZE = 5 * 1024;
private static final ObjectMapper objectMapper = new ObjectMapper();
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final Random RND = new Random();
/**
* Convert JSON to a CBOR equivalent.
@@ -126,62 +127,69 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
}
protected static ObjectMapper getMapper() {
return objectMapper;
return OBJECT_MAPPER;
}
protected ResultActions postDeploymentFeedback(final String controllerId, final Long actionId, final String content,
final ResultMatcher statusMatcher) throws Exception {
return postDeploymentFeedback(MediaType.APPLICATION_JSON_UTF8, controllerId, actionId, content.getBytes(),
statusMatcher);
return postDeploymentFeedback(MediaType.APPLICATION_JSON_UTF8, controllerId, actionId, content.getBytes(), statusMatcher);
}
protected ResultActions putInstalledBase(final String controllerId, final String content,
final ResultMatcher statusMatcher) throws Exception {
protected ResultActions putInstalledBase(final String controllerId, final String content, final ResultMatcher statusMatcher)
throws Exception {
return mvc.perform(put(INSTALLED_BASE_ROOT, tenantAware.getCurrentTenant(), controllerId)
.content(content.getBytes()).contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(statusMatcher);
.andDo(MockMvcResultPrinter.print())
.andExpect(statusMatcher);
}
protected ResultActions postDeploymentFeedback(final MediaType mediaType, final String controllerId,
protected ResultActions postDeploymentFeedback(
final MediaType mediaType, final String controllerId,
final Long actionId, final byte[] content, final ResultMatcher statusMatcher) throws Exception {
return mvc
.perform(post(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(), controllerId, actionId)
.content(content).contentType(mediaType).accept(mediaType))
.andDo(MockMvcResultPrinter.print()).andExpect(statusMatcher);
.andDo(MockMvcResultPrinter.print())
.andExpect(statusMatcher);
}
protected ResultActions postCancelFeedback(final String controllerId, final Long actionId, final String content,
protected ResultActions postCancelFeedback(
final String controllerId, final Long actionId, final String content,
final ResultMatcher statusMatcher) throws Exception {
return postCancelFeedback(MediaType.APPLICATION_JSON_UTF8, controllerId, actionId, content.getBytes(),
statusMatcher);
return postCancelFeedback(MediaType.APPLICATION_JSON_UTF8, controllerId, actionId, content.getBytes(), statusMatcher);
}
protected ResultActions postCancelFeedback(final MediaType mediaType, final String controllerId,
protected ResultActions postCancelFeedback(
final MediaType mediaType, final String controllerId,
final Long actionId, final byte[] content, final ResultMatcher statusMatcher) throws Exception {
return mvc
.perform(post(CANCEL_FEEDBACK, tenantAware.getCurrentTenant(), controllerId, actionId).content(content)
.contentType(mediaType).accept(mediaType))
.andDo(MockMvcResultPrinter.print()).andExpect(statusMatcher);
.andDo(MockMvcResultPrinter.print())
.andExpect(statusMatcher);
}
protected ResultActions performGet(final String url, final MediaType mediaType, final ResultMatcher statusMatcher,
final String... values) throws Exception {
protected ResultActions performGet(final String url, final MediaType mediaType, final ResultMatcher statusMatcher, final String... values)
throws Exception {
return mvc.perform(MockMvcRequestBuilders.get(url, values).accept(mediaType)
.with(new RequestOnHawkbitDefaultPortPostProcessor()))
.andDo(MockMvcResultPrinter.print()).andExpect(statusMatcher)
.andDo(MockMvcResultPrinter.print())
.andExpect(statusMatcher)
.andExpect(content().contentTypeCompatibleWith(mediaType));
}
protected ResultActions getAndVerifyDeploymentBasePayload(final String controllerId, final MediaType mediaType,
protected ResultActions getAndVerifyDeploymentBasePayload(
final String controllerId, final MediaType mediaType,
final DistributionSet ds, final Artifact artifact, final Artifact artifactSignature, final Long actionId,
final Long osModuleId, final String downloadType, final String updateType) throws Exception {
final ResultActions resultActions = performGet(DEPLOYMENT_BASE, mediaType, status().isOk(),
tenantAware.getCurrentTenant(), controllerId, actionId.toString());
return verifyBasePayload("$.deployment", resultActions, controllerId, ds, artifact, artifactSignature, actionId, osModuleId,
downloadType, updateType);
return verifyBasePayload(
"$.deployment", resultActions, controllerId, ds, artifact, artifactSignature, actionId, osModuleId, downloadType, updateType);
}
protected ResultActions getAndVerifyDeploymentBasePayload(final String controllerId, final MediaType mediaType,
protected ResultActions getAndVerifyDeploymentBasePayload(
final String controllerId, final MediaType mediaType,
final DistributionSet ds, final Artifact artifact, final Artifact artifactSignature, final Long actionId,
final Long osModuleId, final Action.ActionType actionType) throws Exception {
return getAndVerifyDeploymentBasePayload(controllerId, mediaType, ds, artifact, artifactSignature, actionId,
@@ -198,127 +206,139 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
}
protected String installedBaseLink(final String controllerId, final String actionId) {
return HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId
+ "/installedBase/" + actionId;
return HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" +
controllerId + "/installedBase/" + actionId;
}
protected String deploymentBaseLink(final String controllerId, final String actionId) {
return HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId
+ "/deploymentBase/" + actionId;
return HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" +
controllerId + "/deploymentBase/" + actionId;
}
protected String getJsonRejectedCancelActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.REJECTED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("rejected"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.REJECTED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("rejected"));
}
protected String getJsonRejectedDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.REJECTED, DdiResult.FinalResult.NONE,
Collections.singletonList("rejected"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.REJECTED, DdiResult.FinalResult.NONE, Collections.singletonList("rejected"));
}
protected String getJsonDownloadDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.DOWNLOAD, DdiResult.FinalResult.NONE,
Collections.singletonList("download"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.DOWNLOAD, DdiResult.FinalResult.NONE, Collections.singletonList("download"));
}
protected String getJsonDownloadedDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.DOWNLOADED, DdiResult.FinalResult.NONE,
Collections.singletonList("download"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.DOWNLOADED, DdiResult.FinalResult.NONE, Collections.singletonList("download"));
}
protected String getJsonCanceledCancelActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CANCELED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("canceled"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.CANCELED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("canceled"));
}
protected String getJsonCanceledDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CANCELED, DdiResult.FinalResult.NONE,
Collections.singletonList("canceled"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.CANCELED, DdiResult.FinalResult.NONE, Collections.singletonList("canceled"));
}
protected String getJsonScheduledCancelActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("scheduled"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("scheduled"));
}
protected String getJsonScheduledDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.NONE,
Collections.singletonList("scheduled"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.NONE, Collections.singletonList("scheduled"));
}
protected String getJsonResumedCancelActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.RESUMED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("resumed"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.RESUMED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("resumed"));
}
protected String getJsonResumedDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.RESUMED, DdiResult.FinalResult.NONE,
Collections.singletonList("resumed"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.RESUMED, DdiResult.FinalResult.NONE, Collections.singletonList("resumed"));
}
protected String getJsonProceedingCancelActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("proceeding"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.SUCCESS, Collections.singletonList("proceeding"));
}
protected String getJsonProceedingDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE,
Collections.singletonList("proceeding"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE, Collections.singletonList("proceeding"));
}
protected String getJsonClosedCancelActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("closed"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("closed"));
}
protected String getJsonClosedDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.NONE,
Collections.singletonList("closed"));
return getJsonActionFeedback(
DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.NONE, Collections.singletonList("closed"));
}
protected String getJsonActionFeedback(final DdiStatus.ExecutionStatus executionStatus,
final DdiResult.FinalResult finalResult) throws JsonProcessingException {
return getJsonActionFeedback(executionStatus, finalResult,
Collections.singletonList(RandomStringUtils.randomAlphanumeric(1000)));
protected String getJsonActionFeedback(
final DdiStatus.ExecutionStatus executionStatus, final DdiResult.FinalResult finalResult) throws JsonProcessingException {
return getJsonActionFeedback(
executionStatus, finalResult, Collections.singletonList(RandomStringUtils.randomAlphanumeric(1000)));
}
protected String getJsonActionFeedback(final DdiStatus.ExecutionStatus executionStatus, final DdiResult ddiResult,
protected String getJsonActionFeedback(
final DdiStatus.ExecutionStatus executionStatus, final DdiResult ddiResult,
final List<String> messages) throws JsonProcessingException {
final DdiStatus ddiStatus = new DdiStatus(executionStatus, ddiResult, null, messages);
return objectMapper.writeValueAsString(new DdiActionFeedback(Instant.now().toString(), ddiStatus));
return OBJECT_MAPPER.writeValueAsString(new DdiActionFeedback(Instant.now().toString(), ddiStatus));
}
protected String getJsonActionFeedback(final DdiStatus.ExecutionStatus executionStatus,
protected String getJsonActionFeedback(
final DdiStatus.ExecutionStatus executionStatus,
final DdiResult.FinalResult finalResult, final List<String> messages) throws JsonProcessingException {
return getJsonActionFeedback(executionStatus, finalResult, null, messages);
}
protected String getJsonActionFeedback(final DdiStatus.ExecutionStatus executionStatus,
protected String getJsonActionFeedback(
final DdiStatus.ExecutionStatus executionStatus,
final DdiResult.FinalResult finalResult, final Integer code, final List<String> messages) throws JsonProcessingException {
final DdiStatus ddiStatus = new DdiStatus(executionStatus, new DdiResult(finalResult, new DdiProgress(2, 5)), code,
messages);
return objectMapper.writeValueAsString(new DdiActionFeedback(Instant.now().toString(), ddiStatus));
final DdiStatus ddiStatus = new DdiStatus(executionStatus, new DdiResult(finalResult, new DdiProgress(2, 5)), code, messages);
return OBJECT_MAPPER.writeValueAsString(new DdiActionFeedback(Instant.now().toString(), ddiStatus));
}
protected String getJsonConfirmationFeedback(final DdiConfirmationFeedback.Confirmation confirmation,
protected String getJsonConfirmationFeedback(
final DdiConfirmationFeedback.Confirmation confirmation,
final Integer code, final List<String> messages) throws JsonProcessingException {
return objectMapper.writeValueAsString(new DdiConfirmationFeedback(confirmation, code, messages));
return OBJECT_MAPPER.writeValueAsString(new DdiConfirmationFeedback(confirmation, code, messages));
}
protected String getJsonInstalledBase(String name, String version) throws JsonProcessingException {
return objectMapper.writeValueAsString(new DdiAssignedVersion(name, version));
return OBJECT_MAPPER.writeValueAsString(new DdiAssignedVersion(name, version));
}
protected ResultActions getAndVerifyConfirmationBasePayload(final String controllerId, final MediaType mediaType,
protected ResultActions getAndVerifyConfirmationBasePayload(
final String controllerId, final MediaType mediaType,
final DistributionSet ds, final Artifact artifact, final Artifact artifactSignature, final Long actionId,
final Long osModuleId, final String downloadType, final String updateType) throws Exception {
final ResultActions resultActions = performGet(CONFIRMATION_BASE_ACTION, mediaType, status().isOk(),
final ResultActions resultActions = performGet(
CONFIRMATION_BASE_ACTION, mediaType, status().isOk(),
tenantAware.getCurrentTenant(), controllerId, actionId.toString());
return verifyBasePayload("$.confirmation", resultActions, controllerId, ds, artifact, artifactSignature, actionId, osModuleId,
return verifyBasePayload(
"$.confirmation", resultActions, controllerId, ds, artifact, artifactSignature, actionId, osModuleId,
downloadType, updateType);
}
static byte[] nextBytes(final int size) {
final byte[] bytes = new byte[size];
RND.nextBytes(bytes);
return bytes;
}
static void implicitLock(final DistributionSet set) {
((JpaDistributionSet) set).setOptLockRevision(set.getOptLockRevision() + 1);
}
@@ -330,7 +350,8 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
return "attempt";
}
private ResultActions verifyBasePayload(final String prefix, final ResultActions resultActions, final String controllerId,
private ResultActions verifyBasePayload(
final String prefix, final ResultActions resultActions, final String controllerId,
final DistributionSet ds, final Artifact artifact, final Artifact artifactSignature, final Long actionId,
final Long osModuleId, final String downloadType, final String updateType) throws Exception {
return resultActions.andExpect(jsonPath("$.id", equalTo(String.valueOf(actionId))))
@@ -354,13 +375,11 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
.andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[0].hashes.sha256",
contains(artifact.getSha256Hash())))
.andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[0]._links.download-http.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId
+ "/softwaremodules/" + osModuleId + "/artifacts/" + artifact.getFilename()
+ "/download")))
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId +
"/softwaremodules/" + osModuleId + "/artifacts/" + artifact.getFilename() + "/download")))
.andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[0]._links.md5sum-http.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId
+ "/softwaremodules/" + osModuleId + "/artifacts/" + artifact.getFilename()
+ "/download.MD5SUM")))
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId +
"/softwaremodules/" + osModuleId + "/artifacts/" + artifact.getFilename() + "/download.MD5SUM")))
.andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[1].size", contains(ARTIFACT_SIZE)))
.andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[1].filename",
contains(artifactSignature.getFilename())))
@@ -371,13 +390,11 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
.andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[1].hashes.sha256",
contains(artifactSignature.getSha256Hash())))
.andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[1]._links.download-http.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId
+ "/softwaremodules/" + osModuleId + "/artifacts/" + artifactSignature.getFilename()
+ "/download")))
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId +
"/softwaremodules/" + osModuleId + "/artifacts/" + artifactSignature.getFilename() + "/download")))
.andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[1]._links.md5sum-http.href",
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId
+ "/softwaremodules/" + osModuleId + "/artifacts/" + artifactSignature.getFilename()
+ "/download.MD5SUM")))
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId +
"/softwaremodules/" + osModuleId + "/artifacts/" + artifactSignature.getFilename() + "/download.MD5SUM")))
.andExpect(jsonPath(prefix + ".chunks[?(@.part=='bApp')].version",
contains(ds.findFirstModuleByType(appType).get().getVersion())))
.andExpect(jsonPath(prefix + ".chunks[?(@.part=='bApp')].metadata").doesNotExist())

View File

@@ -10,7 +10,7 @@
package org.eclipse.hawkbit.ddi.rest.resource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
@@ -24,6 +24,7 @@ import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
@@ -32,7 +33,6 @@ import java.util.TimeZone;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomUtils;
import org.eclipse.hawkbit.ddi.rest.resource.DdiArtifactDownloadTest.DownloadTestConfiguration;
import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
import org.eclipse.hawkbit.repository.model.Artifact;
@@ -74,30 +74,34 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
public void invalidRequestsOnArtifactResource() throws Exception {
// create target
final Target target = testdataFactory.createTarget();
final List<Target> targets = Arrays.asList(target);
final List<Target> targets = Collections.singletonList(target);
// create ds
final DistributionSet ds = testdataFactory.createDistributionSet("");
// create artifact
final int artifactSize = 5 * 1024;
final byte random[] = RandomUtils.nextBytes(artifactSize);
final Artifact artifact = artifactManagement.create(new ArtifactUpload(new ByteArrayInputStream(random),
ds.findFirstModuleByType(osType).get().getId(), "file1", false, artifactSize));
final byte[] random = nextBytes(artifactSize);
final Artifact artifact = artifactManagement.create(new ArtifactUpload(
new ByteArrayInputStream(random), ds.findFirstModuleByType(osType).get().getId(), "file1", false, artifactSize));
assignDistributionSet(ds, targets);
// no artifact available
mvc.perform(get("/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/123455",
target.getControllerId(), getOsModule(ds))).andExpect(status().isNotFound());
target.getControllerId(), getOsModule(ds)))
.andExpect(status().isNotFound());
mvc.perform(get("/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/123455.MD5SUM",
target.getControllerId(), getOsModule(ds))).andExpect(status().isNotFound());
target.getControllerId(), getOsModule(ds)))
.andExpect(status().isNotFound());
// SM does not exist
mvc.perform(get("/controller/v1/{controllerId}/softwaremodules/1234567890/artifacts/{filename}",
target.getControllerId(), artifact.getFilename())).andExpect(status().isNotFound());
target.getControllerId(), artifact.getFilename()))
.andExpect(status().isNotFound());
mvc.perform(get("/controller/v1/{controllerId}/softwaremodules/1234567890/artifacts/{filename}.MD5SUM",
target.getControllerId(), artifact.getFilename())).andExpect(status().isNotFound());
target.getControllerId(), artifact.getFilename()))
.andExpect(status().isNotFound());
// test now consistent data to test allowed methods
mvc.perform(get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}",
@@ -163,34 +167,35 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
// create target
final Target target = testdataFactory.createTarget();
final List<Target> targets = Arrays.asList(target);
final List<Target> targets = Collections.singletonList(target);
// create ds
final DistributionSet ds = testdataFactory.createDistributionSet("");
// create artifact
final int artifactSize = (int) quotaManagement.getMaxArtifactSize();
final byte random[] = RandomUtils.nextBytes(artifactSize);
final byte[] random = nextBytes(artifactSize);
final Artifact artifact = artifactManagement.create(new ArtifactUpload(new ByteArrayInputStream(random),
ds.findFirstModuleByType(osType).get().getId(), "file1", false, artifactSize));
// download fails as artifact is not yet assigned
mvc.perform(get("/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
target.getControllerId(), getOsModule(ds), artifact.getFilename())).andExpect(status().isNotFound());
target.getControllerId(), getOsModule(ds), artifact.getFilename()))
.andExpect(status().isNotFound());
// now assign and download successful
assignDistributionSet(ds, targets);
final MvcResult result = mvc.perform(get(
"/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM))
.andExpect(header().string("Accept-Ranges", "bytes"))
.andExpect(header().string("Last-Modified", dateFormat.format(new Date(artifact.getCreatedAt()))))
.andExpect(header().string("Content-Disposition", "attachment;filename=" + artifact.getFilename()))
.andReturn();
assertTrue(
Arrays.equals(result.getResponse().getContentAsByteArray(), random),
assertArrayEquals(result.getResponse().getContentAsByteArray(), random,
"The same file that was uploaded is expected when downloaded");
// download complete
@@ -209,7 +214,7 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
// create artifact
final int artifactSize = 5 * 1024;
final byte random[] = RandomUtils.nextBytes(artifactSize);
final byte[] random = nextBytes(artifactSize);
final Artifact artifact = artifactManagement.create(
new ArtifactUpload(new ByteArrayInputStream(random), getOsModule(ds), "file1", false, artifactSize));
@@ -219,7 +224,8 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
final MvcResult result = mvc.perform(get(
"/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}.MD5SUM",
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()))
.andExpect(status().isOk()).andExpect(header().string("Content-Disposition",
.andExpect(status().isOk())
.andExpect(header().string("Content-Disposition",
"attachment;filename=" + artifact.getFilename() + ".MD5SUM"))
.andReturn();
@@ -233,7 +239,7 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
public void rangeDownloadArtifact() throws Exception {
// create target
final Target target = testdataFactory.createTarget();
final List<Target> targets = Arrays.asList(target);
final List<Target> targets = Collections.singletonList(target);
// create ds
final DistributionSet ds = testdataFactory.createDistributionSet("");
@@ -241,7 +247,7 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
final int resultLength = (int) quotaManagement.getMaxArtifactSize();
// create artifact
final byte random[] = RandomUtils.nextBytes(resultLength);
final byte[] random = nextBytes(resultLength);
final Artifact artifact = artifactManagement.create(
new ArtifactUpload(new ByteArrayInputStream(random), getOsModule(ds), "file1", false, resultLength));
@@ -255,19 +261,21 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
// full file download with standard range request
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
for (int i = 0; i < resultLength / range; i++) {
final String rangeString = "" + i * range + "-" + ((i + 1) * range - 1);
final String rangeString = i * range + "-" + ((i + 1) * range - 1);
final MvcResult result = mvc.perform(get(
"/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1").header("Range",
"bytes=" + rangeString))
.andExpect(status().isPartialContent()).andExpect(header().string("ETag", artifact.getSha1Hash()))
.andExpect(status().isPartialContent())
.andExpect(header().string("ETag", artifact.getSha1Hash()))
.andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM))
.andExpect(header().string("Accept-Ranges", "bytes"))
.andExpect(header().string("Last-Modified", dateFormat.format(new Date(artifact.getCreatedAt()))))
.andExpect(header().longValue("Content-Length", range))
.andExpect(header().string("Content-Range", "bytes " + rangeString + "/" + resultLength))
.andExpect(header().string("Content-Disposition", "attachment;filename=file1")).andReturn();
.andExpect(header().string("Content-Disposition", "attachment;filename=file1"))
.andReturn();
outputStream.write(result.getResponse().getContentAsByteArray());
}
@@ -279,14 +287,16 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1")
.header("Range", "bytes=-1000"))
.andExpect(status().isPartialContent()).andExpect(header().string("ETag", artifact.getSha1Hash()))
.andExpect(status().isPartialContent())
.andExpect(header().string("ETag", artifact.getSha1Hash()))
.andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM))
.andExpect(header().string("Accept-Ranges", "bytes"))
.andExpect(header().string("Last-Modified", dateFormat.format(new Date(artifact.getCreatedAt()))))
.andExpect(header().longValue("Content-Length", 1000))
.andExpect(header().string("Content-Range",
"bytes " + (resultLength - 1000) + "-" + (resultLength - 1) + "/" + resultLength))
.andExpect(header().string("Content-Disposition", "attachment;filename=file1")).andReturn();
.andExpect(header().string("Content-Disposition", "attachment;filename=file1"))
.andReturn();
assertThat(result.getResponse().getContentAsByteArray())
.isEqualTo(Arrays.copyOfRange(random, resultLength - 1000, resultLength));
@@ -296,14 +306,16 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1")
.header("Range", "bytes=1000-"))
.andExpect(status().isPartialContent()).andExpect(header().string("ETag", artifact.getSha1Hash()))
.andExpect(status().isPartialContent())
.andExpect(header().string("ETag", artifact.getSha1Hash()))
.andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM))
.andExpect(header().string("Accept-Ranges", "bytes"))
.andExpect(header().string("Last-Modified", dateFormat.format(new Date(artifact.getCreatedAt()))))
.andExpect(header().longValue("Content-Length", resultLength - 1000))
.andExpect(header().string("Content-Range",
"bytes " + 1000 + "-" + (resultLength - 1) + "/" + resultLength))
.andExpect(header().string("Content-Disposition", "attachment;filename=file1")).andReturn();
.andExpect(header().string("Content-Disposition", "attachment;filename=file1"))
.andReturn();
assertThat(result.getResponse().getContentAsByteArray())
.isEqualTo(Arrays.copyOfRange(random, 1000, resultLength));
@@ -325,11 +337,13 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1")
.header("Range", "bytes=0-9,10-19"))
.andExpect(status().isPartialContent()).andExpect(header().string("ETag", artifact.getSha1Hash()))
.andExpect(status().isPartialContent())
.andExpect(header().string("ETag", artifact.getSha1Hash()))
.andExpect(content().contentType("multipart/byteranges; boundary=THIS_STRING_SEPARATES_MULTIPART"))
.andExpect(header().string("Accept-Ranges", "bytes"))
.andExpect(header().string("Last-Modified", dateFormat.format(new Date(artifact.getCreatedAt()))))
.andExpect(header().string("Content-Disposition", "attachment;filename=file1")).andReturn();
.andExpect(header().string("Content-Disposition", "attachment;filename=file1"))
.andReturn();
outputStream.reset();
@@ -365,5 +379,4 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
}
}
}
}

View File

@@ -68,8 +68,10 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
.perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId(), tenantAware.getCurrentTenant())
.accept(DdiRestConstants.MEDIA_TYPE_CBOR))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR)).andReturn().getResponse()
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR))
.andReturn().getResponse()
.getContentAsByteArray();
assertThat(JsonPathUtils.<String> evaluate(cborToJson(result), "$.id"))
.isEqualTo(String.valueOf(cancelAction.getId()));
@@ -81,7 +83,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(jsonToCbor(getJsonProceedingCancelActionFeedback()))
.contentType(DdiRestConstants.MEDIA_TYPE_CBOR).accept(DdiRestConstants.MEDIA_TYPE_CBOR))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
}
@Test
@@ -102,7 +105,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonRejectedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
final long current = System.currentTimeMillis();
@@ -110,7 +114,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
mvc.perform(
get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/" + actionId,
tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(actionId))))
.andExpect(jsonPath("$.deployment.download", equalTo("forced")))
@@ -128,7 +133,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.NONE,
Collections.singletonList("message")))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// check database after test
assertThat(deploymentManagement.getAssignedDistributionSet(TestdataFactory.DEFAULT_CONTROLLER_ID).get())
@@ -152,8 +158,10 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
final long timeBeforeFirstPoll = System.currentTimeMillis();
mvc.perform(get("/{tenant}/controller/v1/{controller}", tenantAware.getCurrentTenant(),
TestdataFactory.DEFAULT_CONTROLLER_ID).accept(MediaTypes.HAL_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaTypes.HAL_JSON))
TestdataFactory.DEFAULT_CONTROLLER_ID).accept(MediaTypes.HAL_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
startsWith("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/"
@@ -181,7 +189,9 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
final long timeBefore2ndPoll = System.currentTimeMillis();
mvc.perform(get("/{tenant}/controller/v1/{controller}", tenantAware.getCurrentTenant(),
TestdataFactory.DEFAULT_CONTROLLER_ID)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
TestdataFactory.DEFAULT_CONTROLLER_ID))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.cancelAction.href",
@@ -193,7 +203,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
mvc.perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId(), tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(cancelAction.getId()))))
.andExpect(jsonPath("$.cancelAction.stopId", equalTo(String.valueOf(actionId))));
@@ -205,7 +216,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON)
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
activeActionsByTarget = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent();
@@ -222,27 +234,32 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// not allowed methods
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/1",
tenantAware.getCurrentTenant())).andDo(MockMvcResultPrinter.print())
tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(put("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/1",
tenantAware.getCurrentTenant())).andDo(MockMvcResultPrinter.print())
tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(delete("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/1",
tenantAware.getCurrentTenant())).andDo(MockMvcResultPrinter.print())
tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
// non existing target
mvc.perform(get("/{tenant}/controller/v1/34534543/cancelAction/1", tenantAware.getCurrentTenant())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
createCancelAction("34534543");
// wrong media type
mvc.perform(get("/{tenant}/controller/v1/34534543/cancelAction/1", tenantAware.getCurrentTenant())
.accept(MediaType.APPLICATION_ATOM_XML)).andDo(MockMvcResultPrinter.print())
.accept(MediaType.APPLICATION_ATOM_XML))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotAcceptable());
}
@@ -267,7 +284,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonProceedingCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
assertThat(countActionStatusAll()).isEqualTo(3);
@@ -276,7 +294,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonResumedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
assertThat(countActionStatusAll()).isEqualTo(4);
@@ -284,7 +303,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonScheduledCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(countActionStatusAll()).isEqualTo(5);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
@@ -294,7 +314,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonCanceledCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(countActionStatusAll()).isEqualTo(6);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
@@ -307,7 +328,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonRejectedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(countActionStatusAll()).isEqualTo(7);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
@@ -316,7 +338,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(countActionStatusAll()).isEqualTo(8);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).isEmpty();
}
@@ -352,14 +375,17 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
assertThat(deploymentManagement.countActionsByTarget(savedTarget.getControllerId())).isEqualTo(3);
mvc.perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId(), tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(cancelAction.getId()))))
.andExpect(jsonPath("$.cancelAction.stopId", equalTo(String.valueOf(actionId))));
assertThat(countActionStatusAll()).isEqualTo(6);
mvc.perform(get("/{tenant}/controller/v1/{controllerId}", tenantAware.getCurrentTenant(),
TestdataFactory.DEFAULT_CONTROLLER_ID)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
TestdataFactory.DEFAULT_CONTROLLER_ID))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.cancelAction.href",
@@ -371,7 +397,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(countActionStatusAll()).isEqualTo(7);
// 1 update actions, 1 cancel actions
@@ -379,14 +406,17 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
assertThat(deploymentManagement.countActionsByTarget(savedTarget.getControllerId())).isEqualTo(3);
mvc.perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction2.getId(), tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(cancelAction2.getId()))))
.andExpect(jsonPath("$.cancelAction.stopId", equalTo(String.valueOf(actionId2))));
assertThat(countActionStatusAll()).isEqualTo(8);
mvc.perform(get("/{tenant}/controller/v1/{controller}", tenantAware.getCurrentTenant(),
TestdataFactory.DEFAULT_CONTROLLER_ID)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
TestdataFactory.DEFAULT_CONTROLLER_ID))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.cancelAction.href",
@@ -398,7 +428,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction2.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(countActionStatusAll()).isEqualTo(9);
assertThat(deploymentManagement.getAssignedDistributionSet(TestdataFactory.DEFAULT_CONTROLLER_ID).get())
@@ -406,7 +437,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
mvc.perform(
get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/" + actionId3,
tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(countActionStatusAll()).isEqualTo(10);
// 1 update actions, 0 cancel actions
@@ -422,7 +454,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
mvc.perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction3.getId(), tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(cancelAction3.getId()))))
.andExpect(jsonPath("$.cancelAction.stopId", equalTo(String.valueOf(actionId3))));
@@ -433,7 +466,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction3.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(countActionStatusAll()).isEqualTo(13);
// final status
@@ -480,49 +514,57 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(delete("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
// bad content type
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_ATOM_XML)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isUnsupportedMediaType());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isUnsupportedMediaType());
// bad body
String invalidFeedback = "{\"status\":{\"execution\":\"546456456\",\"result\":{\"finished\":\"none\",\"progress\":{\"cnt\":2,\"of\":5}},\"details\":\"none\"]}}";
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).content(invalidFeedback)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
// non existing target
mvc.perform(post("/{tenant}/controller/v1/12345/cancelAction/" + cancelAction.getId() + "/feedback",
tenantAware.getCurrentTenant()).content(getJsonClosedCancelActionFeedback())
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
// invalid action
invalidFeedback = "{\"id\":\"sdfsdfsdfs\",\"status\":{\"execution\":\"closed\",\"result\":{\"finished\":\"none\",\"progress\":{\"cnt\":2,\"of\":5}},\"details\":\"details\"]}}";
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).content(invalidFeedback)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
// finaly, get it right :)
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
}
private Action createCancelAction(final String targetid) {

View File

@@ -52,10 +52,10 @@ import org.springframework.test.context.ActiveProfiles;
@Story("Config Data Resource")
class DdiConfigDataTest extends AbstractDDiApiIntegrationTest {
public static final String TARGET1_ID = "4717";
public static final String TARGET1_CONFIGDATA_PATH = "/{tenant}/controller/v1/" + TARGET1_ID + "/configData";
public static final String TARGET2_ID = "4718";
public static final String TARGET2_CONFIGDATA_PATH = "/{tenant}/controller/v1/" + TARGET2_ID + "/configData";
private static final String TARGET1_ID = "4717";
private static final String TARGET1_CONFIG_DATA_PATH = "/{tenant}/controller/v1/" + TARGET1_ID + "/configData";
private static final String TARGET2_ID = "4718";
private static final String TARGET2_CONFIG_DATA_PATH = "/{tenant}/controller/v1/" + TARGET2_ID + "/configData";
@Test
@Description("Verify that config data can be uploaded as CBOR")
@@ -65,31 +65,31 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest {
final Map<String, String> attributes = new HashMap<>();
attributes.put(ATTRIBUTE_KEY_VALID, ATTRIBUTE_VALUE_VALID);
mvc.perform(put(TARGET1_CONFIGDATA_PATH, tenantAware.getCurrentTenant())
mvc.perform(put(TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant())
.content(jsonToCbor(JsonBuilder.configData(attributes).toString()))
.contentType(DdiRestConstants.MEDIA_TYPE_CBOR)).andDo(MockMvcResultPrinter.print())
.contentType(DdiRestConstants.MEDIA_TYPE_CBOR))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(targetManagement.getControllerAttributes(TARGET1_ID)).isEqualTo(attributes);
}
@Test
@Description("We verify that the config data (i.e. device attributes like serial number, hardware revision etc.) "
+ "are requested only once from the device.")
@Description("We verify that the config data (i.e. device attributes like serial number, hardware revision etc.) " +
"are requested only once from the device.")
@SuppressWarnings("squid:S2925")
void requestConfigDataIfEmpty() throws Exception {
final Target savedTarget = testdataFactory.createTarget("4712");
final long current = System.currentTimeMillis();
mvc.perform(
get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()).accept(MediaTypes.HAL_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()).accept(MediaTypes.HAL_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.configData.href", equalTo(
"http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/configData")));
Thread.sleep(1); // is required: otherwise processing the next line is
// often too fast and
// the following assert will fail
// often too fast and // the following assert will fail
assertThat(targetManagement.getByControllerID("4712").orElseThrow(NoSuchElementException::new)
.getLastTargetQuery())
.isLessThanOrEqualTo(System.currentTimeMillis());
@@ -97,26 +97,23 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest {
.getLastTargetQuery())
.isGreaterThanOrEqualTo(current);
final Map<String, String> attributes = new HashMap<>(1);
attributes.put("dsafsdf", "sdsds");
final Target updateControllerAttributes = controllerManagement
.updateControllerAttributes(savedTarget.getControllerId(), attributes, null);
.updateControllerAttributes(savedTarget.getControllerId(), Map.of("dsafsdf", "sdsds"), null);
// request controller attributes need to be false because we don't want
// to request the controller attributes again
assertThat(updateControllerAttributes.isRequestControllerAttributes()).isFalse();
mvc.perform(
get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()).accept(MediaTypes.HAL_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()).accept(MediaTypes.HAL_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.configData.href").doesNotExist());
}
@Test
@Description("We verify that the config data (i.e. device attributes like serial number, hardware revision etc.) "
+ "can be uploaded correctly by the controller.")
@Description("We verify that the config data (i.e. device attributes like serial number, hardware revision etc.) " +
"can be uploaded correctly by the controller.")
void putConfigData() throws Exception {
testdataFactory.createTarget(TARGET1_ID);
@@ -124,38 +121,38 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest {
final Map<String, String> attributes = new HashMap<>();
attributes.put(ATTRIBUTE_KEY_VALID, ATTRIBUTE_VALUE_VALID);
mvc.perform(put(TARGET1_CONFIGDATA_PATH, tenantAware.getCurrentTenant())
mvc.perform(put(TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(targetManagement.getControllerAttributes(TARGET1_ID)).isEqualTo(attributes);
// update
attributes.put("sdsds", "123412");
mvc.perform(put(TARGET1_CONFIGDATA_PATH, tenantAware.getCurrentTenant())
mvc.perform(put(TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(targetManagement.getControllerAttributes(TARGET1_ID)).isEqualTo(attributes);
}
@Test
@Description("We verify that the config data (i.e. device attributes like serial number, hardware revision etc.) "
+ "upload quota is enforced to protect the server from malicious attempts.")
@Description("We verify that the config data (i.e. device attributes like serial number, hardware revision etc.) " +
"upload quota is enforced to protect the server from malicious attempts.")
void putTooMuchConfigData() throws Exception {
testdataFactory.createTarget(TARGET1_ID);
// initial
Map<String, String> attributes = new HashMap<>();
final Map<String, String> attributes = new HashMap<>();
for (int i = 0; i < quotaManagement.getMaxAttributeEntriesPerTarget(); i++) {
attributes.put("dsafsdf" + i, "sdsds" + i);
}
mvc.perform(put(TARGET1_CONFIGDATA_PATH, tenantAware.getCurrentTenant())
mvc.perform(put(TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
attributes = new HashMap<>();
attributes.put("on too many", "sdsds");
mvc.perform(put(TARGET1_CONFIGDATA_PATH, tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON))
mvc.perform(put(TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(Map.of("on too many", "sdsds")).toString()).contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
@@ -174,27 +171,31 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest {
andExpect(status().isMethodNotAllowed());
mvc.perform(get("/{tenant}/controller/v1/4712/configData", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(delete("/{tenant}/controller/v1/4712/configData", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
// bad content type
final Map<String, String> attributes = new HashMap<>();
attributes.put("dsafsdf", "sdsds");
final Map<String, String> attributes = Map.of("dsafsdf", "sdsds");
mvc.perform(put("/{tenant}/controller/v1/4712/configData", tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(attributes).toString()).contentType(MediaTypes.HAL_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isUnsupportedMediaType());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isUnsupportedMediaType());
// non existing target
mvc.perform(put("/{tenant}/controller/v1/456456/configData", tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
// bad body
mvc.perform(put("/{tenant}/controller/v1/4712/configData", tenantAware.getCurrentTenant())
.content("{\"id\": \"51659181\"}").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
}
@Test
@@ -209,7 +210,6 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Verify that config data (device attributes) can be updated by the controller using different update modes (merge, replace, remove).")
void putConfigDataWithDifferentUpdateModes() throws Exception {
// create a target
testdataFactory.createTarget(TARGET1_ID);
@@ -232,7 +232,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest {
@Step
private void putAndVerifyConfigDataWithKeyTooLong() throws Exception {
final Map<String, String> attributes = Collections.singletonMap(ATTRIBUTE_KEY_TOO_LONG, ATTRIBUTE_VALUE_VALID);
mvc.perform(put(DdiConfigDataTest.TARGET2_CONFIGDATA_PATH, tenantAware.getCurrentTenant())
mvc.perform(put(DdiConfigDataTest.TARGET2_CONFIG_DATA_PATH, tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.exceptionClass", equalTo(InvalidTargetAttributeException.class.getName())))
@@ -242,7 +242,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest {
@Step
private void putAndVerifyConfigDataWithValueTooLong() throws Exception {
final Map<String, String> attributes = Collections.singletonMap(ATTRIBUTE_KEY_VALID, ATTRIBUTE_VALUE_TOO_LONG);
mvc.perform(put(DdiConfigDataTest.TARGET2_CONFIGDATA_PATH, tenantAware.getCurrentTenant())
mvc.perform(put(DdiConfigDataTest.TARGET2_CONFIG_DATA_PATH, tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.exceptionClass", equalTo(InvalidTargetAttributeException.class.getName())))
@@ -252,14 +252,15 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest {
@Step
private void putConfigDataWithInvalidUpdateMode() throws Exception {
// create some attriutes
final Map<String, String> attributes = new HashMap<>();
attributes.put("k0", "v0");
attributes.put("k1", "v1");
final Map<String, String> attributes = Map.of(
"k0", "v0",
"k1", "v1");
// use an invalid update mode
mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIGDATA_PATH, tenantAware.getCurrentTenant())
mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(attributes, "KJHGKJHGKJHG").toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
}
@@ -269,13 +270,14 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest {
final int previousSize = targetManagement.getControllerAttributes(DdiConfigDataTest.TARGET1_ID).size();
// update the attributes using update mode REMOVE
final Map<String, String> removeAttributes = new HashMap<>();
removeAttributes.put("k1", "foo");
removeAttributes.put("k3", "bar");
final Map<String, String> removeAttributes = Map.of(
"k1", "foo",
"k3", "bar");
mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIGDATA_PATH, tenantAware.getCurrentTenant())
mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(removeAttributes, "remove").toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// verify attribute removal
@@ -287,74 +289,68 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest {
}
@Step
private void putConfigDataWithUpdateModeMerge()
throws Exception {
private void putConfigDataWithUpdateModeMerge() throws Exception {
// get the current attributes
final Map<String, String> attributes = new HashMap<>(
targetManagement.getControllerAttributes(DdiConfigDataTest.TARGET1_ID));
final Map<String, String> attributes = new HashMap<>(targetManagement.getControllerAttributes(DdiConfigDataTest.TARGET1_ID));
// update the attributes using update mode MERGE
final Map<String, String> mergeAttributes = new HashMap<>();
mergeAttributes.put("k1", "v1_modified_again");
mergeAttributes.put("k4", "v4");
mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIGDATA_PATH, tenantAware.getCurrentTenant())
final Map<String, String> mergeAttributes = Map.of(
"k1", "v1_modified_again",
"k4", "v4");
mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(mergeAttributes, "merge").toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// verify attribute merge
final Map<String, String> updatedAttributes = targetManagement
.getControllerAttributes(DdiConfigDataTest.TARGET1_ID);
final Map<String, String> updatedAttributes = targetManagement.getControllerAttributes(DdiConfigDataTest.TARGET1_ID);
assertThat(updatedAttributes).hasSize(4);
assertThat(updatedAttributes).containsAllEntriesOf(mergeAttributes);
assertThat(updatedAttributes).containsEntry("k1", "v1_modified_again");
attributes.keySet().forEach(assertThat(updatedAttributes)::containsKey);
}
@Step
private void putConfigDataWithUpdateModeReplace()
throws Exception {
private void putConfigDataWithUpdateModeReplace() throws Exception {
// get the current attributes
final Map<String, String> attributes = new HashMap<>(
targetManagement.getControllerAttributes(DdiConfigDataTest.TARGET1_ID));
final Map<String, String> attributes = new HashMap<>(targetManagement.getControllerAttributes(DdiConfigDataTest.TARGET1_ID));
// update the attributes using update mode REPLACE
final Map<String, String> replacementAttributes = new HashMap<>();
replacementAttributes.put("k1", "v1_modified");
replacementAttributes.put("k2", "v2");
replacementAttributes.put("k3", "v3");
mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIGDATA_PATH, tenantAware.getCurrentTenant())
final Map<String, String> replacementAttributes = Map.of(
"k1", "v1_modified",
"k2", "v2",
"k3", "v3");
mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(replacementAttributes, "replace").toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// verify attribute replacement
final Map<String, String> updatedAttributes = targetManagement
.getControllerAttributes(DdiConfigDataTest.TARGET1_ID);
final Map<String, String> updatedAttributes = targetManagement.getControllerAttributes(DdiConfigDataTest.TARGET1_ID);
assertThat(updatedAttributes).hasSize(replacementAttributes.size());
assertThat(updatedAttributes).containsAllEntriesOf(replacementAttributes);
assertThat(updatedAttributes).containsEntry("k1", "v1_modified");
attributes.entrySet().forEach(assertThat(updatedAttributes)::doesNotContain);
}
@Step
private void putConfigDataWithoutUpdateMode()
throws Exception {
// create some attriutes
final Map<String, String> attributes = new HashMap<>();
attributes.put("k0", "v0");
attributes.put("k1", "v1");
private void putConfigDataWithoutUpdateMode() throws Exception {
// create some attributes
final Map<String, String> attributes = Map.of(
"k0", "v0",
"k1", "v1");
// set the initial attributes
mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIGDATA_PATH, tenantAware.getCurrentTenant())
mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant())
.content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// verify the initial parameters
final Map<String, String> updatedAttributes = targetManagement
.getControllerAttributes(DdiConfigDataTest.TARGET1_ID);
assertThat(updatedAttributes).containsExactlyEntriesOf(attributes);
}
}
}

View File

@@ -29,7 +29,6 @@ import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.eclipse.hawkbit.ddi.json.model.DdiActivateAutoConfirmation;
import org.eclipse.hawkbit.ddi.json.model.DdiConfirmationFeedback;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
@@ -80,44 +79,41 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
// Prepare test data
final DistributionSet ds = testdataFactory.createDistributionSet("", true);
final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true);
final Artifact artifact = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE), getOsModule(ds),
"test1", ARTIFACT_SIZE);
final Artifact artifactSignature = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
getOsModule(ds), "test1.signature", ARTIFACT_SIZE);
final Artifact artifact = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE), getOsModule(ds), "test1", ARTIFACT_SIZE);
final Artifact artifactSignature = testdataFactory.createArtifact(
nextBytes(ARTIFACT_SIZE), getOsModule(ds), "test1.signature", ARTIFACT_SIZE);
final Target savedTarget = testdataFactory.createTarget(DdiConfirmationBaseTest.DEFAULT_CONTROLLER_ID);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).isEmpty();
final List<Target> targetsAssignedToDs = assignDistributionSet(ds.getId(), savedTarget.getControllerId(),
Action.ActionType.FORCED).getAssignedEntity().stream().map(Action::getTarget)
final List<Target> targetsAssignedToDs = assignDistributionSet(
ds.getId(), savedTarget.getControllerId(), Action.ActionType.FORCED).getAssignedEntity().stream()
.map(Action::getTarget)
.collect(Collectors.toList());
implicitLock(ds);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
assertThat(deploymentManagement.countActionsAll()).isEqualTo(1);
assignDistributionSet(ds2, targetsAssignedToDs).getAssignedEntity();
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(2);
assertThat(deploymentManagement.countActionsAll()).isEqualTo(2);
final Action uaction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action uaction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
assertThat(uaction.getDistributionSet()).isEqualTo(ds);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(2);
// Run test
final long current = System.currentTimeMillis();
final String expectedConfirmationBaseLink = String.format("/%s/controller/v1/%s/confirmationBase/%d",
final String expectedConfirmationBaseLink = String.format(
"/%s/controller/v1/%s/confirmationBase/%d",
tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, uaction.getId());
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID)
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID)
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.confirmationBase.href",
containsString(expectedConfirmationBaseLink)))
.andExpect(jsonPath("$._links.confirmationBase.href", containsString(expectedConfirmationBaseLink)))
.andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist());
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery())
@@ -128,7 +124,8 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
final DistributionSet findDistributionSetByAction = distributionSetManagement.getByAction(action.getId()).get();
getAndVerifyConfirmationBasePayload(DEFAULT_CONTROLLER_ID, MediaType.APPLICATION_JSON, ds, artifact,
getAndVerifyConfirmationBasePayload(
DEFAULT_CONTROLLER_ID, MediaType.APPLICATION_JSON, ds, artifact,
artifactSignature, action.getId(),
findDistributionSetByAction.findFirstModuleByType(osType).get().getId(), "forced", "forced");
@@ -151,8 +148,7 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(distributionSet.getId(), target.getName());
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId())
.getContent().get(0);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId()).getContent().get(0);
// get confirmation base
performGet(CONFIRMATION_BASE_ACTION, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR),
@@ -172,17 +168,16 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
savedTarget = getFirstAssignedTarget(assignDistributionSet(ds.getId(), savedTarget.getControllerId()));
final String controllerId = savedTarget.getControllerId();
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent().get(0);
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent()
.get(0);
mvc.perform(
get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.confirmationBase.href").doesNotExist());
mvc.perform(get(CONFIRMATION_BASE_ACTION, tenantAware.getCurrentTenant(), controllerId, savedAction.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@@ -197,20 +192,21 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
final String controllerId = savedTarget.getControllerId();
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent()
.get(0);
mvc.perform(
get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent().get(0);
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.confirmationBase.href").exists())
.andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist());
mvc.perform(get(CONFIRMATION_BASE_ACTION, tenantAware.getCurrentTenant(), controllerId, savedAction.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), controllerId, savedAction.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@@ -225,8 +221,7 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
final String controllerId = savedTarget.getControllerId();
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent()
.get(0);
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent().get(0);
// disable confirmation flow
disableConfirmationFlow();
@@ -235,15 +230,17 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
verifyActionInConfirmationBaseState(savedTarget.getControllerId(), savedAction.getId());
// verify confirmation endpoint is still accessible
sendConfirmationFeedback(savedTarget, savedAction, DdiConfirmationFeedback.Confirmation.DENIED, 20,
"Action denied message.").andExpect(status().isOk());
sendConfirmationFeedback(
savedTarget, savedAction, DdiConfirmationFeedback.Confirmation.DENIED, 20, "Action denied message.")
.andExpect(status().isOk());
// confirmation base should still be exposed
verifyActionInConfirmationBaseState(savedTarget.getControllerId(), savedAction.getId());
// verify confirmation endpoint is still accessible
sendConfirmationFeedback(savedTarget, savedAction, DdiConfirmationFeedback.Confirmation.CONFIRMED, 10,
"Action confirmed message.").andExpect(status().isOk());
sendConfirmationFeedback(
savedTarget, savedAction, DdiConfirmationFeedback.Confirmation.CONFIRMED, 10, "Action confirmed message.")
.andExpect(status().isOk());
// assert deployment link is exposed to the target
verifyActionInDeploymentBaseState(controllerId, savedAction.getId());
@@ -251,7 +248,8 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Controller sends a confirmed action state.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@@ -273,8 +271,9 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent()
.get(0);
sendConfirmationFeedback(savedTarget, savedAction, DdiConfirmationFeedback.Confirmation.CONFIRMED, 10,
"Action confirmed message.").andExpect(status().isOk());
sendConfirmationFeedback(
savedTarget, savedAction, DdiConfirmationFeedback.Confirmation.CONFIRMED, 10, "Action confirmed message.")
.andExpect(status().isOk());
// assert deployment link is exposed to the target
verifyActionInDeploymentBaseState(controllerId, savedAction.getId());
@@ -287,18 +286,19 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
final String controllerId = testdataFactory.createTarget("989").getControllerId();
assignDistributionSet(testdataFactory.createDistributionSet("").getId(), controllerId);
final long actionId = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent().get(0)
.getId();
final long actionId = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent().get(0).getId();
final String confirmationBaseActionLink = String.format("/%s/controller/v1/%s/confirmationBase/%d",
final String confirmationBaseActionLink = String.format(
"/%s/controller/v1/%s/confirmationBase/%d",
tenantAware.getCurrentTenant(), controllerId, actionId);
final String activateAutoConfLink = String.format("/%s/controller/v1/%s/confirmationBase/activateAutoConfirm",
final String activateAutoConfLink = String.format(
"/%s/controller/v1/%s/confirmationBase/activateAutoConfirm",
tenantAware.getCurrentTenant(), controllerId);
mvc.perform(
get(CONFIRMATION_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
mvc.perform(get(CONFIRMATION_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("autoConfirm.active", equalTo(Boolean.FALSE)))
.andExpect(jsonPath("$._links.confirmationBase.href", containsString(confirmationBaseActionLink)))
.andExpect(jsonPath("$._links.activateAutoConfirm.href", containsString(activateAutoConfLink)))
@@ -308,23 +308,24 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
@ParameterizedTest
@MethodSource("possibleActiveStates")
@Description("Confirmation base provides right values if auto-confirm is active.")
void getConfirmationBaseProvidesAutoConfirmStatusActive(final String initiator, final String remark)
throws Exception {
void getConfirmationBaseProvidesAutoConfirmStatusActive(final String initiator, final String remark) throws Exception {
final String controllerId = testdataFactory.createTarget("988").getControllerId();
confirmationManagement.activateAutoConfirmation(controllerId, initiator, remark);
final String deactivateAutoConfLink = String.format(
"/%s/controller/v1/%s/confirmationBase/deactivateAutoConfirm", tenantAware.getCurrentTenant(),
controllerId);
"/%s/controller/v1/%s/confirmationBase/deactivateAutoConfirm",
tenantAware.getCurrentTenant(), controllerId);
mvc.perform(
get(CONFIRMATION_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
mvc.perform(get(CONFIRMATION_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("autoConfirm.active", equalTo(Boolean.TRUE)))
.andExpect(initiator == null ? jsonPath("autoConfirm.initiator").doesNotExist()
.andExpect(initiator == null
? jsonPath("autoConfirm.initiator").doesNotExist()
: jsonPath("autoConfirm.initiator", equalTo(initiator)))
.andExpect(remark == null ? jsonPath("autoConfirm.remark").doesNotExist()
.andExpect(remark == null
? jsonPath("autoConfirm.remark").doesNotExist()
: jsonPath("autoConfirm.remark", equalTo(remark)))
.andExpect(jsonPath("$._links.deactivateAutoConfirm.href", containsString(deactivateAutoConfLink)))
.andExpect(jsonPath("$._links.activateAutoConfirm").doesNotExist());
@@ -340,7 +341,8 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
mvc.perform(post(ACTIVATE_AUTO_CONFIRM, tenantAware.getCurrentTenant(), controllerId)
.content(getMapper().writeValueAsString(body)).contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(confirmationManagement.getStatus(controllerId)).hasValueSatisfying(status -> {
assertThat(status.getInitiator()).isEqualTo(initiator);
@@ -357,14 +359,16 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
confirmationManagement.activateAutoConfirmation(controllerId, null, null);
mvc.perform(post(DEACTIVATE_AUTO_CONFIRM, tenantAware.getCurrentTenant(), controllerId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(confirmationManagement.getStatus(controllerId)).isEmpty();
}
@Test
@Description("Controller sends a denied action state.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@@ -383,30 +387,33 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
Target savedTarget = testdataFactory.createTarget("989");
savedTarget = getFirstAssignedTarget(assignDistributionSet(ds.getId(), savedTarget.getControllerId()));
String controllerId = savedTarget.getControllerId();
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent()
.get(0);
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent().get(0);
sendConfirmationFeedback(savedTarget, savedAction, DdiConfirmationFeedback.Confirmation.DENIED, 10,
"Action denied message.").andExpect(status().isOk());
sendConfirmationFeedback(
savedTarget, savedAction, DdiConfirmationFeedback.Confirmation.DENIED, 10, "Action denied message.")
.andExpect(status().isOk());
// asserts that deployment link is not available
final String expectedConfirmationBaseLink = String.format("/%s/controller/v1/%s/confirmationBase/%d",
final String expectedConfirmationBaseLink = String.format(
"/%s/controller/v1/%s/confirmationBase/%d",
tenantAware.getCurrentTenant(), controllerId, savedAction.getId());
mvc.perform(
get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist())
.andExpect(jsonPath("$._links.confirmationBase.href", containsString(expectedConfirmationBaseLink)));
mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), controllerId, savedAction.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@Test
@Description("Test to verify that only a specific count of messages are returned based on the input actionHistory for getControllerDeploymentActionFeedback endpoint.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@@ -422,71 +429,80 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
Target savedTarget = testdataFactory.createTarget("990");
savedTarget = getFirstAssignedTarget(assignDistributionSet(ds.getId(), savedTarget.getControllerId()));
String controllerId = savedTarget.getControllerId();
final String controllerId = savedTarget.getControllerId();
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent()
.get(0);
final String CONFIRMED_MESSAGE = "Action confirmed message.";
final Integer CONFIRMED_CODE = 10;
sendConfirmationFeedback(savedTarget, savedAction, DdiConfirmationFeedback.Confirmation.CONFIRMED,
CONFIRMED_CODE, CONFIRMED_MESSAGE).andExpect(status().isOk());
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, controllerId).getContent().get(0);
final String confirmedMessage = "Action confirmed message.";
final Integer confirmedCode = 10;
sendConfirmationFeedback(
savedTarget, savedAction, DdiConfirmationFeedback.Confirmation.CONFIRMED, confirmedCode, confirmedMessage)
.andExpect(status().isOk());
// confirmationBase not available in RUNNING state anymore
mvc.perform(get(CONFIRMATION_BASE_ACTION, tenantAware.getCurrentTenant(), savedTarget.getControllerId(),
savedAction.getId()).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
// assert confirmed message against deploymentBase endpoint
// this call will update the action due to retrieved action status update
mvc.perform(
get(DEPLOYMENT_BASE + "?actionHistory=2", tenantAware.getCurrentTenant(), savedTarget.getControllerId(),
savedAction.getId()).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages", hasItem(containsString(CONFIRMED_MESSAGE))))
mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=2", tenantAware.getCurrentTenant(), savedTarget.getControllerId(),
savedAction.getId()).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages", hasItem(containsString(confirmedMessage))))
.andExpect(jsonPath("$.actionHistory.messages",
hasItem(containsString(String.format(CONFIRMATION_CODE_MSG_PREFIX, CONFIRMED_CODE)))));
hasItem(containsString(String.format(CONFIRMATION_CODE_MSG_PREFIX, confirmedCode)))));
}
private static Stream<Arguments> possibleActiveStates() {
return Stream.of(Arguments.of("someInitiator", "someRemark"), Arguments.of(null, "someRemark"),
Arguments.of("someInitiator", null), Arguments.of(null, null));
return Stream.of(
Arguments.of("someInitiator", "someRemark"),
Arguments.of(null, "someRemark"),
Arguments.of("someInitiator", null),
Arguments.of(null, null));
}
@Step
private void verifyActionInDeploymentBaseState(final String controllerId, final long actionId) throws Exception {
final String expectedDeploymentBaseLink = String.format("/%s/controller/v1/%s/deploymentBase/%d",
final String expectedDeploymentBaseLink = String.format(
"/%s/controller/v1/%s/deploymentBase/%d",
tenantAware.getCurrentTenant(), controllerId, actionId);
mvc.perform(
get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.deploymentBase.href", containsString(expectedDeploymentBaseLink)))
.andExpect(jsonPath("$._links.confirmationBase.href").doesNotExist());
// assert that deployment endpoint is working
mvc.perform(get(expectedDeploymentBaseLink).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
}
@Step
private void verifyActionInConfirmationBaseState(final String controllerId, final long actionId) throws Exception {
mvc.perform(
get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.confirmationBase.href").exists())
.andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist());
mvc.perform(get(CONFIRMATION_BASE_ACTION, tenantAware.getCurrentTenant(), controllerId, actionId)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), controllerId, actionId)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
private ResultActions sendConfirmationFeedback(final Target target, final Action action,
private ResultActions sendConfirmationFeedback(
final Target target, final Action action,
final DdiConfirmationFeedback.Confirmation confirmation, Integer code, String message) throws Exception {
if (message == null) {
message = RandomStringUtils.randomAlphanumeric(1000);
}

View File

@@ -30,7 +30,6 @@ import com.jayway.jsonpath.JsonPath;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomUtils;
import org.assertj.core.api.Condition;
import org.eclipse.hawkbit.ddi.json.model.DdiResult;
import org.eclipse.hawkbit.ddi.json.model.DdiStatus;
@@ -94,8 +93,7 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
testdataFactory.createArtifacts(softwareModuleId);
assignDistributionSet(distributionSet.getId(), target.getName());
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId())
.getContent().get(0);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId()).getContent().get(0);
// get deployment base
performGet(DEPLOYMENT_BASE, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), status().isOk(),
@@ -107,17 +105,17 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
String.valueOf(softwareModuleId));
final byte[] feedback = jsonToCbor(getJsonProceedingDeploymentActionFeedback());
postDeploymentFeedback(MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), target.getControllerId(),
action.getId(), feedback, status().isOk());
postDeploymentFeedback(
MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), target.getControllerId(), action.getId(), feedback,
status().isOk());
}
@Test
@Description("Ensures that artifacts are not found, when software module does not exists.")
void artifactsNotFound() throws Exception {
final Target target = testdataFactory.createTarget();
performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isNotFound(),
tenantAware.getCurrentTenant(), target.getControllerId(), "1");
performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isNotFound(), tenantAware.getCurrentTenant(),
target.getControllerId(), "1");
}
@Test
@@ -131,8 +129,8 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(distributionSet.getId(), target.getName());
performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isOk(),
tenantAware.getCurrentTenant(), target.getControllerId(), softwareModuleId.toString())
performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(),
target.getControllerId(), softwareModuleId.toString())
.andExpect(jsonPath("$", hasSize(3)))
.andExpect(jsonPath("$.[?(@.filename=='filename0')]", hasSize(1)))
.andExpect(jsonPath("$.[?(@.filename=='filename1')]", hasSize(1)))
@@ -145,36 +143,37 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
// Prepare test data
final DistributionSet ds = testdataFactory.createDistributionSet("", true);
final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true);
final Artifact artifact = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE), getOsModule(ds),
"test1", ARTIFACT_SIZE);
final Artifact artifactSignature = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
getOsModule(ds), "test1.signature", ARTIFACT_SIZE);
final Artifact artifact = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE), getOsModule(ds), "test1", ARTIFACT_SIZE);
final Artifact artifactSignature = testdataFactory.createArtifact(
nextBytes(ARTIFACT_SIZE), getOsModule(ds), "test1.signature", ARTIFACT_SIZE);
final Target savedTarget = createTargetAndAssertNoActiveActions();
final List<Target> targetsAssignedToDs = assignDistributionSet(ds.getId(), savedTarget.getControllerId(),
ActionType.FORCED).getAssignedEntity().stream().map(Action::getTarget).collect(Collectors.toList());
final List<Target> targetsAssignedToDs = assignDistributionSet(ds.getId(), savedTarget.getControllerId(), ActionType.FORCED)
.getAssignedEntity().stream()
.map(Action::getTarget)
.collect(Collectors.toList());
implicitLock(ds);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
assertThat(deploymentManagement.countActionsAll()).isEqualTo(1);
assignDistributionSet(ds2, targetsAssignedToDs).getAssignedEntity();
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(2);
assertThat(deploymentManagement.countActionsAll()).isEqualTo(2);
final Action uaction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action uaction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
assertThat(uaction.getDistributionSet()).isEqualTo(ds);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(2);
// Run test
final long current = System.currentTimeMillis();
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID).andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
DEFAULT_CONTROLLER_ID)
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath(
"$._links.deploymentBase.href",
startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString()))));
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery())
.isGreaterThanOrEqualTo(current);
@@ -183,7 +182,6 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assertThat(countActionStatusAll()).isEqualTo(2);
final DistributionSet findDistributionSetByAction = distributionSetManagement.getByAction(action.getId()).get();
getAndVerifyDeploymentBasePayload(DEFAULT_CONTROLLER_ID, MediaType.APPLICATION_JSON, ds, artifact,
artifactSignature, action.getId(),
findDistributionSetByAction.findFirstModuleByType(osType).get().getId(), "forced", "forced");
@@ -207,14 +205,16 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
ActionType.TIMEFORCED, System.currentTimeMillis() + 2_000));
MvcResult mvcResult = performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(),
tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID).andReturn();
tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID)
.andReturn();
final String urlBeforeSwitch = JsonPath.compile("_links.deploymentBase.href")
.read(mvcResult.getResponse().getContentAsString()).toString();
// Time is not yet over, so we should see the same URL
mvcResult = performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID).andReturn();
DEFAULT_CONTROLLER_ID)
.andReturn();
assertThat(JsonPath.compile("_links.deploymentBase.href").read(mvcResult.getResponse().getContentAsString())
.toString()).isEqualTo(urlBeforeSwitch)
.startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, actionId.toString()));
@@ -223,7 +223,8 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
TimeUnit.MILLISECONDS.sleep(2_000);
mvcResult = performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID).andReturn();
DEFAULT_CONTROLLER_ID)
.andReturn();
assertThat(JsonPath.compile("_links.deploymentBase.href").read(mvcResult.getResponse().getContentAsString())
.toString()).isNotEqualTo(urlBeforeSwitch);
@@ -238,9 +239,9 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final String visibleMetadataOsKey = "metaDataVisible";
final String visibleMetadataOsValue = "withValue";
final Artifact artifact = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE), getOsModule(ds),
final Artifact artifact = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE), getOsModule(ds),
"test1", ARTIFACT_SIZE);
final Artifact artifactSignature = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifactSignature = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds), "test1.signature", ARTIFACT_SIZE);
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(getOsModule(ds))
@@ -255,23 +256,21 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
implicitLock(ds);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
assertThat(deploymentManagement.countActionsAll()).isEqualTo(1);
assignDistributionSet(ds2, saved).getAssignedEntity();
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(2);
assertThat(deploymentManagement.countActionsAll()).isEqualTo(2);
final Action uaction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action uaction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
assertThat(uaction.getDistributionSet()).isEqualTo(ds);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(2);
// Run test
final long current = System.currentTimeMillis();
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID).andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
DEFAULT_CONTROLLER_ID)
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString()))));
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery())
@@ -301,9 +300,8 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final DistributionSet ds = testdataFactory.createDistributionSet("", true);
final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true);
final Artifact artifact = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE), getOsModule(ds),
"test1", ARTIFACT_SIZE);
final Artifact artifactSignature = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifact = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE), getOsModule(ds), "test1", ARTIFACT_SIZE);
final Artifact artifactSignature = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds), "test1.signature", ARTIFACT_SIZE);
final Target savedTarget = createTargetAndAssertNoActiveActions();
@@ -313,23 +311,21 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
implicitLock(ds);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
assertThat(deploymentManagement.countActionsAll()).isEqualTo(1);
assignDistributionSet(ds2, saved).getAssignedEntity();
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(2);
assertThat(countActionStatusAll()).isEqualTo(2);
final Action uaction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action uaction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
assertThat(uaction.getDistributionSet()).isEqualTo(ds);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(2);
// Run test
final long current = System.currentTimeMillis();
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID).andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
DEFAULT_CONTROLLER_ID)
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString()))));
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery())
@@ -339,7 +335,6 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assertThat(countActionStatusAll()).isEqualTo(2);
final DistributionSet findDistributionSetByAction = distributionSetManagement.getByAction(action.getId()).get();
getAndVerifyDeploymentBasePayload(DEFAULT_CONTROLLER_ID, MediaType.APPLICATION_JSON, ds, artifact,
artifactSignature, action.getId(),
findDistributionSetByAction.findFirstModuleByType(osType).get().getId(), "forced", "forced");
@@ -362,10 +357,9 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
// Prepare test data
final DistributionSet ds = testdataFactory.createDistributionSet("", true);
final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true);
final Artifact artifact = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE), getOsModule(ds),
"test1", ARTIFACT_SIZE);
final Artifact artifactSignature = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
getOsModule(ds), "test1.signature", ARTIFACT_SIZE);
final Artifact artifact = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE), getOsModule(ds), "test1", ARTIFACT_SIZE);
final Artifact artifactSignature = testdataFactory.createArtifact(
nextBytes(ARTIFACT_SIZE), getOsModule(ds), "test1.signature", ARTIFACT_SIZE);
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(getOsModule(ds))
.key("metaDataVisible").value("withValue").targetVisible(true));
@@ -374,21 +368,20 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final Target savedTarget = createTargetAndAssertNoActiveActions();
final List<Target> saved = assignDistributionSet(ds.getId(), savedTarget.getControllerId(),
ActionType.DOWNLOAD_ONLY).getAssignedEntity().stream().map(Action::getTarget)
final List<Target> saved = assignDistributionSet(ds.getId(), savedTarget.getControllerId(), ActionType.DOWNLOAD_ONLY)
.getAssignedEntity().stream()
.map(Action::getTarget)
.collect(Collectors.toList());
implicitLock(ds);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
assertThat(deploymentManagement.countActionsAll()).isEqualTo(1);
assignDistributionSet(ds2, saved).getAssignedEntity();
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(2);
assertThat(deploymentManagement.countActionsAll()).isEqualTo(2);
final Action uaction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action uaction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
assertThat(uaction.getDistributionSet()).isEqualTo(ds);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(2);
@@ -396,7 +389,8 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final long current = System.currentTimeMillis();
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID).andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
DEFAULT_CONTROLLER_ID)
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString()))));
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery())
@@ -406,7 +400,6 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assertThat(countActionStatusAll()).isEqualTo(2);
final DistributionSet findDistributionSetByAction = distributionSetManagement.getByAction(action.getId()).get();
getAndVerifyDeploymentBasePayload(DEFAULT_CONTROLLER_ID, MediaType.APPLICATION_JSON, ds, "metaDataVisible",
"withValue", artifact, artifactSignature, action.getId(), "forced", "skip",
getOsModule(findDistributionSetByAction));
@@ -426,22 +419,26 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
// not allowed methods
mvc.perform(post(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "1"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(put(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "1"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(delete(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "1"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
// non existing target
mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "not-existing", "1"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
// no deployment
mvc.perform(
MockMvcRequestBuilders.get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "1"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "1"))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
// wrong media type
final List<Target> toAssign = Collections.singletonList(target);
@@ -449,23 +446,25 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final Long actionId = getFirstAssignedActionId(assignDistributionSet(savedSet, toAssign));
mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID,
actionId)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
actionId))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
mvc.perform(MockMvcRequestBuilders
.get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, actionId)
.accept(MediaType.APPLICATION_ATOM_XML)).andDo(MockMvcResultPrinter.print())
.accept(MediaType.APPLICATION_ATOM_XML))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotAcceptable());
}
@Test
@Description("The server protects itself against to many feedback upload attempts. The test verifies that "
+ "it is not possible to exceed the configured maximum number of feedback uploads.")
@Description("The server protects itself against to many feedback upload attempts. The test verifies that " +
"it is not possible to exceed the configured maximum number of feedback uploads.")
void tooMuchDeploymentActionFeedback() throws Exception {
final Target target = testdataFactory.createTarget(DEFAULT_CONTROLLER_ID);
final DistributionSet ds = testdataFactory.createDistributionSet("");
assignDistributionSet(ds.getId(), DEFAULT_CONTROLLER_ID);
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0);
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent().get(0);
final String feedback = getJsonProceedingDeploymentActionFeedback();
// assign distribution set creates an action status, so only 99 left
@@ -477,23 +476,21 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
}
@Test
@Description("The server protects itself against too large feedback bodies. The test verifies that "
+ "it is not possible to exceed the configured maximum number of feedback details.")
@Description("The server protects itself against too large feedback bodies. The test verifies that " +
"it is not possible to exceed the configured maximum number of feedback details.")
void tooMuchDeploymentActionMessagesInFeedback() throws Exception {
final Target target = testdataFactory.createTarget(DEFAULT_CONTROLLER_ID);
final DistributionSet ds = testdataFactory.createDistributionSet("");
assignDistributionSet(ds.getId(), DEFAULT_CONTROLLER_ID);
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0);
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent().get(0);
final List<String> messages = new ArrayList<>();
for (int i = 0; i < quotaManagement.getMaxMessagesPerActionStatus() + 1; i++) {
messages.add(String.valueOf(i));
}
final String feedback = getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE,
null, messages);
final String feedback = getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE, null, messages);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action.getId(), feedback, status().isForbidden());
}
@@ -519,27 +516,21 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assertThat(targetManagement.findByUpdateStatus(PageRequest.of(0, 10), TargetUpdateStatus.UNKNOWN)).hasSize(2);
// action1 done
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId1, getJsonClosedDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId1, getJsonClosedDeploymentActionFeedback(), status().isOk());
findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.PENDING, 2,
Optional.of(ds1));
findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.PENDING, 2, Optional.of(ds1));
assertStatusMessagesCount(4);
// action2 done
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId2, getJsonClosedDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId2, getJsonClosedDeploymentActionFeedback(), status().isOk());
findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.PENDING, 1,
Optional.of(ds2));
findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.PENDING, 1, Optional.of(ds2));
assertStatusMessagesCount(5);
// action3 done
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId3, getJsonClosedDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId3, getJsonClosedDeploymentActionFeedback(), status().isOk());
findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.IN_SYNC, 0,
Optional.of(ds3));
findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.IN_SYNC, 0, Optional.of(ds3));
assertStatusMessagesCount(6);
}
@@ -549,16 +540,15 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
DistributionSet ds = testdataFactory.createDistributionSet("");
final Target savedTarget = testdataFactory.createTarget(DEFAULT_CONTROLLER_ID);
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getUpdateStatus())
.isEqualTo(TargetUpdateStatus.UNKNOWN);
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getUpdateStatus()).isEqualTo(TargetUpdateStatus.UNKNOWN);
assignDistributionSet(ds, Collections.singletonList(savedTarget));
final Action action = actionRepository
.findAll(ActionSpecifications.byDistributionSetId(ds.getId()), PAGE)
.map(Action.class::cast).getContent().get(0);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action.getId(),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.FAILURE,
Collections.singletonList("Error message")),
getJsonActionFeedback(
DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.FAILURE, Collections.singletonList("Error message")),
status().isOk());
findTargetAndAssertUpdateStatus(Optional.empty(), TargetUpdateStatus.ERROR, 0, Optional.empty());
@@ -567,60 +557,51 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
// redo
ds = distributionSetManagement.getWithDetails(ds.getId()).get();
assignDistributionSet(ds,
Collections.singletonList(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get()));
final Action action2 = deploymentManagement.findActiveActionsByTarget(PAGE, DEFAULT_CONTROLLER_ID).getContent()
.get(0);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action2.getId(), getJsonClosedCancelActionFeedback(),
status().isOk());
assignDistributionSet(ds, Collections.singletonList(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get()));
final Action action2 = deploymentManagement.findActiveActionsByTarget(PAGE, DEFAULT_CONTROLLER_ID).getContent().get(0);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action2.getId(), getJsonClosedCancelActionFeedback(), status().isOk());
findTargetAndAssertUpdateStatus(Optional.of(ds), TargetUpdateStatus.IN_SYNC, 0, Optional.of(ds));
assertTargetCountByStatus(0, 0, 1);
assertThat(deploymentManagement.findInActiveActionsByTarget(PAGE, DEFAULT_CONTROLLER_ID)).hasSize(2);
assertThat(countActionStatusAll()).isEqualTo(4);
assertThat(deploymentManagement.findActionStatusByAction(PAGE, action.getId()).getContent()).haveAtLeast(1,
new ActionStatusCondition(Status.ERROR));
assertThat(deploymentManagement.findActionStatusByAction(PAGE, action2.getId()).getContent()).haveAtLeast(1,
new ActionStatusCondition(Status.FINISHED));
assertThat(deploymentManagement.findActionStatusByAction(PAGE, action.getId()).getContent())
.haveAtLeast(1, new ActionStatusCondition(Status.ERROR));
assertThat(deploymentManagement.findActionStatusByAction(PAGE, action2.getId()).getContent())
.haveAtLeast(1, new ActionStatusCondition(Status.FINISHED));
}
@Test
@Description("Verifies that the controller can provided as much feedback entries as necessary as long as it is in the configured limits.")
void rootRsSingleDeploymentActionFeedback() throws Exception {
final DistributionSet ds = testdataFactory.createDistributionSet("");
final Long actionId = getFirstAssignedActionId(assignDistributionSet(ds,
Collections.singletonList(testdataFactory.createTarget(DEFAULT_CONTROLLER_ID))));
final Long actionId = getFirstAssignedActionId(
assignDistributionSet(ds,
Collections.singletonList(testdataFactory.createTarget(DEFAULT_CONTROLLER_ID))));
implicitLock(ds);
findTargetAndAssertUpdateStatus(Optional.of(ds), TargetUpdateStatus.PENDING, 1, Optional.empty());
// Now valid Feedback
for (int i = 0; i < 4; i++) {
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonProceedingDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonProceedingDeploymentActionFeedback(), status().isOk());
assertActionStatusCount(i + 2, i);
}
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonScheduledDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonScheduledDeploymentActionFeedback(), status().isOk());
assertActionStatusCount(6, 5);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonResumedDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonResumedDeploymentActionFeedback(), status().isOk());
assertActionStatusCount(7, 6);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonCanceledDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonCanceledDeploymentActionFeedback(), status().isOk());
assertStatusAndActiveActionsCount(TargetUpdateStatus.PENDING, 1);
assertActionStatusCount(8, 7, 0, 0, 1);
assertTargetCountByStatus(1, 0, 0);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonRejectedDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonRejectedDeploymentActionFeedback(), status().isOk());
assertStatusAndActiveActionsCount(TargetUpdateStatus.PENDING, 1);
assertActionStatusCount(9, 6, 1, 0, 1);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonClosedDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonClosedDeploymentActionFeedback(), status().isOk());
assertStatusAndActiveActionsCount(TargetUpdateStatus.IN_SYNC, 0);
assertActionStatusCount(10, 7, 1, 1, 1);
assertTargetCountByStatus(0, 0, 1);
@@ -636,9 +617,7 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final DistributionSet savedSet2 = testdataFactory.createDistributionSet("1");
// target does not exist
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, 1234L, getJsonProceedingDeploymentActionFeedback(),
status().isNotFound());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, 1234L, getJsonProceedingDeploymentActionFeedback(), status().isNotFound());
final Target savedTarget = testdataFactory.createTarget(DEFAULT_CONTROLLER_ID);
@@ -648,8 +627,7 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(savedSet, Collections.singletonList(savedTarget)).getAssignedEntity().iterator().next();
assignDistributionSet(savedSet2, Collections.singletonList(testdataFactory.createTarget("4713")));
final Action updateAction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action updateAction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
// action exists but is not assigned to this target
postDeploymentFeedback("4713", updateAction.getId(), getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING,
@@ -657,53 +635,57 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
// not allowed methods
mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID, "2")).andDo(MockMvcResultPrinter.print())
DEFAULT_CONTROLLER_ID, "2"))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(put(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "2"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(delete(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "2"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
}
@Test
@Description("Ensures that an invalid id in feedback body returns a bad request.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1) })
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1) })
void invalidIdInFeedbackReturnsBadRequest() throws Exception {
final Target target = testdataFactory.createTarget("1080");
final DistributionSet ds = testdataFactory.createDistributionSet("");
assignDistributionSet(ds.getId(), "1080");
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0);
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent().get(0);
final String invalidFeedback = "{\"id\":\"AAAA\",\"status\":{\"execution\":\"proceeding\",\"result\":{\"finished\":\"none\",\"progress\":{\"cnt\":2,\"of\":5}},\"details\":\"details\"]}}";
postDeploymentFeedback("1080", action.getId(), invalidFeedback, status().isBadRequest());
}
@Test
@Description("Ensures that a missing feedback result in feedback body returns a bad request.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1) })
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1) })
void missingResultAttributeInFeedbackReturnsBadRequest() throws Exception {
final Target target = testdataFactory.createTarget("1080");
final DistributionSet ds = testdataFactory.createDistributionSet("");
assignDistributionSet(ds.getId(), "1080");
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0);
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent().get(0);
final String missingResultInFeedback = getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, (DdiResult) null,
Collections.singletonList("test"));
@@ -714,20 +696,21 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Ensures that a missing finished result in feedback body returns a bad request.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1) })
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1) })
void missingFinishedAttributeInFeedbackReturnsBadRequest() throws Exception {
final Target target = testdataFactory.createTarget("1080");
final DistributionSet ds = testdataFactory.createDistributionSet("");
assignDistributionSet(ds.getId(), "1080");
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0);
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent().get(0);
final String missingFinishedResultInFeedback = getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED,
new DdiResult(null, null),
Collections.singletonList("test"));
@@ -741,15 +724,15 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
return actionStatusRepository.count();
}
private void getAndVerifyDeploymentBasePayload(final String controllerId, final MediaType mediaType,
private void getAndVerifyDeploymentBasePayload(
final String controllerId, final MediaType mediaType,
final DistributionSet ds, final String visibleMetadataOsKey, final String visibleMetadataOsValue,
final Artifact artifact, final Artifact artifactSignature, final Long actionId, final String downloadType,
final String updateType, final Long osModuleId) throws Exception {
getAndVerifyDeploymentBasePayload(controllerId, mediaType, ds, artifact, artifactSignature, actionId,
osModuleId, downloadType, updateType).andExpect(
jsonPath("$.deployment.chunks[?(@.part=='os')].metadata[0].key").value(visibleMetadataOsKey))
.andExpect(jsonPath("$.deployment.chunks[?(@.part=='os')].metadata[0].value")
.value(visibleMetadataOsValue));
osModuleId, downloadType, updateType)
.andExpect(jsonPath("$.deployment.chunks[?(@.part=='os')].metadata[0].key").value(visibleMetadataOsKey))
.andExpect(jsonPath("$.deployment.chunks[?(@.part=='os')].metadata[0].value").value(visibleMetadataOsValue));
}
private void assertActionStatusCount(final int actionStatusCount, final int minActionStatusCountInPage) {
@@ -760,8 +743,8 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId())).hasSize(1);
assertThat(countActionStatusAll()).isEqualTo(actionStatusCount);
assertThat(findActionStatusAll(PAGE).getContent()).haveAtLeast(minActionStatusCountInPage,
new ActionStatusCondition(Status.RUNNING));
assertThat(findActionStatusAll(PAGE).getContent())
.haveAtLeast(minActionStatusCountInPage, new ActionStatusCondition(Status.RUNNING));
}
private Target createTargetAndAssertNoActiveActions() {
@@ -774,13 +757,13 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
private void assertStatusMessagesCount(final int actionStatusMessagesCount) {
final Iterable<ActionStatus> actionStatusMessages;
actionStatusMessages = findActionStatusAll(PageRequest.of(0, 100, Direction.DESC, "id"))
.getContent();
actionStatusMessages = findActionStatusAll(PageRequest.of(0, 100, Direction.DESC, "id")).getContent();
assertThat(actionStatusMessages).hasSize(actionStatusMessagesCount);
assertThat(actionStatusMessages).haveAtLeast(1, new ActionStatusCondition(Status.FINISHED));
}
private void findTargetAndAssertUpdateStatus(final Optional<DistributionSet> ds,
private void findTargetAndAssertUpdateStatus(
final Optional<DistributionSet> ds,
final TargetUpdateStatus updateStatus, final int activeActions,
final Optional<DistributionSet> installedDs) {
final Target myT = targetManagement.getByControllerID(DdiDeploymentBaseTest.DEFAULT_CONTROLLER_ID).get();
@@ -791,31 +774,23 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
}
private void assertTargetCountByStatus(final int pending, final int error, final int inSync) {
assertThat(targetManagement.findByUpdateStatus(PageRequest.of(0, 10), TargetUpdateStatus.PENDING))
.hasSize(pending);
assertThat(targetManagement.findByUpdateStatus(PageRequest.of(0, 10), TargetUpdateStatus.PENDING)).hasSize(pending);
assertThat(targetManagement.findByUpdateStatus(PageRequest.of(0, 10), TargetUpdateStatus.ERROR)).hasSize(error);
assertThat(targetManagement.findByUpdateStatus(PageRequest.of(0, 10), TargetUpdateStatus.IN_SYNC))
.hasSize(inSync);
assertThat(targetManagement.findByUpdateStatus(PageRequest.of(0, 10), TargetUpdateStatus.IN_SYNC)).hasSize(inSync);
}
private void assertActionStatusCount(final int total, final int running, final int warning, final int finished,
final int canceled) {
private void assertActionStatusCount(final int total, final int running, final int warning, final int finished, final int canceled) {
assertThat(countActionStatusAll()).isEqualTo(total);
assertThat(findActionStatusAll(PAGE).getContent()).haveAtLeast(running,
new ActionStatusCondition(Status.RUNNING));
assertThat(findActionStatusAll(PAGE).getContent()).haveAtLeast(warning,
new ActionStatusCondition(Status.WARNING));
assertThat(findActionStatusAll(PAGE).getContent()).haveAtLeast(canceled,
new ActionStatusCondition(Status.CANCELED));
assertThat(findActionStatusAll(PAGE).getContent()).haveAtLeast(finished,
new ActionStatusCondition(Status.FINISHED));
assertThat(findActionStatusAll(PAGE).getContent()).haveAtLeast(running, new ActionStatusCondition(Status.RUNNING));
assertThat(findActionStatusAll(PAGE).getContent()).haveAtLeast(warning, new ActionStatusCondition(Status.WARNING));
assertThat(findActionStatusAll(PAGE).getContent()).haveAtLeast(canceled, new ActionStatusCondition(Status.CANCELED));
assertThat(findActionStatusAll(PAGE).getContent()).haveAtLeast(finished, new ActionStatusCondition(Status.FINISHED));
}
private void assertStatusAndActiveActionsCount(final TargetUpdateStatus status, final int activeActions) {
final Target target = targetManagement.getByControllerID(DdiDeploymentBaseTest.DEFAULT_CONTROLLER_ID).get();
assertThat(target.getUpdateStatus()).isEqualTo(status);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId()))
.hasSize(activeActions);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId())).hasSize(activeActions);
}
private Page<ActionStatus> findActionStatusAll(final Pageable pageable) {
@@ -835,4 +810,4 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
return value.getStatus() == status;
}
}
}
}

View File

@@ -30,7 +30,6 @@ import java.util.stream.Stream;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomUtils;
import org.eclipse.hawkbit.ddi.json.model.DdiResult;
import org.eclipse.hawkbit.ddi.json.model.DdiStatus;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
@@ -87,8 +86,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
testdataFactory.createArtifacts(softwareModuleId);
final Long actionId = getFirstAssignedActionId(assignDistributionSet(ds, target));
postDeploymentFeedback(target.getControllerId(), actionId, getJsonClosedDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId, getJsonClosedDeploymentActionFeedback(), status().isOk());
// get installed base
performGet(INSTALLED_BASE, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), status().isOk(),
@@ -107,11 +105,9 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final DistributionSet ds = testdataFactory.createDistributionSet("");
// update assigned version
putInstalledBase(target.getControllerId(), getJsonInstalledBase(ds.getName(), ds.getVersion()), status()
.isCreated());
putInstalledBase(target.getControllerId(), getJsonInstalledBase(ds.getName(), ds.getVersion()), status().isCreated());
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId()).get().getId())
.isEqualTo(ds.getId());
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId()).get().getId()).isEqualTo(ds.getId());
// update assigned version while version already assigned
putInstalledBase(target.getControllerId(), getJsonInstalledBase(ds.getName(), ds.getVersion()), status().isOk());
@@ -137,15 +133,15 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Target target = createTargetAndAssertNoActiveActions();
final DistributionSet ds1 = testdataFactory.createDistributionSet("1", true);
final Artifact artifact1 = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifact1 = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds1), "test1", ARTIFACT_SIZE);
final Artifact artifactSignature1 = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifactSignature1 = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds1), "test1.signature", ARTIFACT_SIZE);
final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true);
final Artifact artifact2 = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifact2 = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds2), "test2", ARTIFACT_SIZE);
final Artifact artifactSignature2 = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifactSignature2 = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds2), "test2.signature", ARTIFACT_SIZE);
// Run test with 1st action
@@ -161,8 +157,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
actionId1, ds1.findFirstModuleByType(osType).get().getId(), Action.ActionType.SOFT);
postDeploymentFeedback(target.getControllerId(), actionId1,
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Closed")),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("Closed")),
status().isOk());
getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds1, artifact1, artifactSignature1,
@@ -182,8 +177,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
actionId2, ds2.findFirstModuleByType(osType).get().getId(), Action.ActionType.FORCED);
postDeploymentFeedback(target.getControllerId(), actionId2,
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Closed")),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("Closed")),
status().isOk());
getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds2, artifact2, artifactSignature2,
@@ -195,8 +189,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
startsWith(installedBaseLink(CONTROLLER_ID, actionId2.toString()))))
.andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist());
// older installed action is still accessible, although not part of controller
// base
// older installed action is still accessible, although not part of controller base
getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds1, artifact1, artifactSignature1,
actionId1, ds1.findFirstModuleByType(osType).get().getId(), Action.ActionType.SOFT);
}
@@ -208,9 +201,9 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Target target = createTargetAndAssertNoActiveActions();
final DistributionSet ds1 = testdataFactory.createDistributionSet("1", true);
final Artifact artifact1 = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifact1 = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds1), "test1", ARTIFACT_SIZE);
final Artifact artifactSignature1 = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifactSignature1 = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds1), "test1.signature", ARTIFACT_SIZE);
// assign ds1, action1 - and provide cancel feedback
@@ -218,8 +211,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
deploymentManagement.cancelAction(actionId1);
postCancelFeedback(target.getControllerId(), actionId1,
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("Canceled")),
status().isOk());
// assign ds1, action2 - and provide cancel feedback
@@ -227,16 +219,14 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.FORCED));
deploymentManagement.cancelAction(actionId2);
postCancelFeedback(target.getControllerId(), actionId2,
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("Canceled")),
status().isOk());
// assign ds1, action 3 - and provide success feedback
final Long actionId3 = getFirstAssignedActionId(
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
postDeploymentFeedback(target.getControllerId(), actionId3,
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("Canceled")),
status().isOk());
// Test: latest succeeded action is returned in installedBase
@@ -251,9 +241,13 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
// cancelled action are not accessible
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(),
actionId1.toString())).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
actionId1.toString()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(),
actionId2.toString())).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
actionId2.toString()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@Test
@@ -263,9 +257,9 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Target target = createTargetAndAssertNoActiveActions();
final DistributionSet ds1 = testdataFactory.createDistributionSet("1", true);
final Artifact artifact1 = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifact1 = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds1), "test1", ARTIFACT_SIZE);
final Artifact artifactSignature1 = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifactSignature1 = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds1), "test1.signature", ARTIFACT_SIZE);
final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true);
@@ -274,8 +268,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Long actionId1 = getFirstAssignedActionId(
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
postDeploymentFeedback(target.getControllerId(), actionId1,
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Success")),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("Success")),
status().isOk());
// assign ds2, action2 - assign ds1, action 3 - and cancel both
@@ -285,13 +278,11 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
deploymentManagement.cancelAction(actionId2);
postCancelFeedback(target.getControllerId(), actionId2,
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("Canceled")),
status().isOk());
deploymentManagement.cancelAction(actionId3);
postCancelFeedback(target.getControllerId(), actionId3,
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("Canceled")),
status().isOk());
// Test: the succeeded action is returned in installedBase instead of the latest
@@ -307,9 +298,13 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
// cancelled action are not accessible
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(),
actionId2.toString())).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
actionId2.toString()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(),
actionId3.toString())).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
actionId3.toString()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@Test
@@ -319,9 +314,9 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Target target = createTargetAndAssertNoActiveActions();
final DistributionSet ds1 = testdataFactory.createDistributionSet("1", true);
final Artifact artifact1 = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifact1 = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds1), "test1", ARTIFACT_SIZE);
final Artifact artifactSignature1 = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifactSignature1 = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds1), "test1.signature", ARTIFACT_SIZE);
final DistributionSet ds2 = testdataFactory.createDistributionSet("2", true);
@@ -330,8 +325,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Long actionId1 = getFirstAssignedActionId(
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
postDeploymentFeedback(target.getControllerId(), actionId1,
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Success")),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("Success")),
status().isOk());
// assign ds2, action2 - assign ds1, action 3 - and cancel action 2
@@ -341,12 +335,10 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
deploymentManagement.cancelAction(actionId2);
postCancelFeedback(target.getControllerId(), actionId2,
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("Canceled")),
status().isOk());
// Test: the succeeded action is returned in installedBase instead of the latest
// cancelled action
// Test: the succeeded action is returned in installedBase instead of the latest cancelled action
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), CONTROLLER_ID)
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.installedBase.href",
@@ -359,9 +351,13 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
// cancelled action are not accessible
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(),
actionId2.toString())).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
actionId2.toString()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(),
actionId3.toString())).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
actionId3.toString()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@Test
@@ -382,7 +378,9 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
target.getControllerId(), actionId.toString());
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(),
actionId.toString())).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
actionId.toString()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@Test
@@ -396,8 +394,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Long actionId = getFirstAssignedActionId(assignDistributionSet(ds, target));
postDeploymentFeedback(target.getControllerId(), actionId, getJsonClosedDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId, getJsonClosedDeploymentActionFeedback(), status().isOk());
performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isOk(),
tenantAware.getCurrentTenant(), target.getControllerId(), softwareModuleId.toString())
@@ -410,13 +407,15 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
@ParameterizedTest
@MethodSource("org.eclipse.hawkbit.ddi.rest.resource.DdiInstalledBaseTest#actionTypeForDeployment")
@Description("Test forced deployment to a controller. Checks that action is represented as installedBase after installation.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 5), // implicit lock
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1) })
@@ -424,26 +423,26 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
// Prepare test data
final Target target = createTargetAndAssertNoActiveActions();
final DistributionSet ds = testdataFactory.createDistributionSet("", true);
final Artifact artifact = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE), getOsModule(ds),
final Artifact artifact = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE), getOsModule(ds),
"test1", ARTIFACT_SIZE);
final Artifact artifactSignature = testdataFactory.createArtifact(RandomUtils.nextBytes(ARTIFACT_SIZE),
final Artifact artifactSignature = testdataFactory.createArtifact(nextBytes(ARTIFACT_SIZE),
getOsModule(ds), "test1.signature", ARTIFACT_SIZE);
final Long actionId = getFirstAssignedActionId(
assignDistributionSet(ds.getId(), target.getControllerId(), actionType));
postDeploymentFeedback(target.getControllerId(), actionId,
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Closed")),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("Closed")),
status().isOk());
// Run test
final ResultActions resultActions = performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(),
tenantAware.getCurrentTenant(), target.getControllerId());
resultActions.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
resultActions.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist())
.andExpect(jsonPath("$._links.installedBase.href",
containsString(String.format("/%s/controller/v1/%s/installedBase/%d",
tenantAware.getCurrentTenant(), target.getControllerId(), actionId))));
.andExpect(jsonPath("$._links.installedBase.href", containsString(String.format(
"/%s/controller/v1/%s/installedBase/%d",
tenantAware.getCurrentTenant(), target.getControllerId(), actionId))));
getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds, artifact, artifactSignature,
actionId, ds.findFirstModuleByType(osType).get().getId(), actionType);
@@ -461,13 +460,15 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Test download-only deployment to a controller. Checks that download-only is not represented as installedBase.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 2) })
@@ -479,18 +480,20 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds.getId(), target.getControllerId(), Action.ActionType.DOWNLOAD_ONLY));
performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(),
target.getControllerId()).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
target.getControllerId())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.deploymentBase.href").exists())
.andExpect(jsonPath("$._links.installedBase.href").doesNotExist());
postDeploymentFeedback(target.getControllerId(), actionId, getJsonDownloadDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId, getJsonDownloadedDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId, getJsonDownloadDeploymentActionFeedback(), status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId, getJsonDownloadedDeploymentActionFeedback(), status().isOk());
// Test
performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(),
target.getControllerId()).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
target.getControllerId())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist())
.andExpect(jsonPath("$._links.installedBase.href").doesNotExist());
}
@@ -506,7 +509,9 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds.getId(), target.getControllerId(), actionType));
performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(),
target.getControllerId()).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
target.getControllerId())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.deploymentBase.href").exists())
.andExpect(jsonPath("$._links.installedBase.href").doesNotExist());
@@ -520,7 +525,9 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
// Test
performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(),
target.getControllerId()).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
target.getControllerId())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist())
.andExpect(jsonPath("$._links.installedBase.href").doesNotExist());
}
@@ -531,8 +538,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final DistributionSet ds = testdataFactory.createDistributionSet("");
Target savedTarget = testdataFactory.createTarget("911");
savedTarget = getFirstAssignedTarget(assignDistributionSet(ds.getId(), savedTarget.getControllerId()));
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(),
getJsonActionFeedback(DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.NONE,
@@ -553,14 +559,15 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
// for zero input no action history is returned
mvc.perform(get(INSTALLED_BASE + "?actionHistory", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages").doesNotExist());
// depending on given query parameter value, only the latest messages are
// returned
// depending on given query parameter value, only the latest messages are returned
mvc.perform(get(INSTALLED_BASE + "?actionHistory=2", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages", hasItem(containsString("Installation completed"))))
.andExpect(jsonPath("$.actionHistory.messages", hasItem(containsString("Installation proceeding"))))
.andExpect(
@@ -569,7 +576,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
// for negative input the entire action history is returned
mvc.perform(get(INSTALLED_BASE + "?actionHistory=-3", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages", hasItem(containsString("Installation completed"))))
.andExpect(jsonPath("$.actionHistory.messages", hasItem(containsString("Installation proceeding"))))
.andExpect(jsonPath("$.actionHistory.messages", hasItem(containsString("Installation scheduled"))));
@@ -582,21 +590,26 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
// not allowed methods
mvc.perform(post(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, "1"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(put(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, "1"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(delete(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, "1"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
// non existing target
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), "not-existing", "1"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
// no deployment
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, "1"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
// wrong media type
final List<Target> toAssign = Collections.singletonList(target);
@@ -605,9 +618,11 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Long actionId = getFirstAssignedActionId(assignDistributionSet(savedSet, toAssign));
postDeploymentFeedback(CONTROLLER_ID, actionId, getJsonClosedCancelActionFeedback(), status().isOk());
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, actionId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, actionId)
.accept(MediaType.APPLICATION_ATOM_XML)).andDo(MockMvcResultPrinter.print())
.accept(MediaType.APPLICATION_ATOM_XML))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotAcceptable());
}
@@ -622,4 +637,4 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
assertThat(actionStatusRepository.count()).isZero();
return savedTarget;
}
}
}

View File

@@ -86,6 +86,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
private static final String TARGET_COMPLETED_INSTALLATION_MSG = "Target completed installation.";
private static final String TARGET_PROCEEDING_INSTALLATION_MSG = "Target proceeding installation.";
private static final String TARGET_SCHEDULED_INSTALLATION_MSG = "Target scheduled installation.";
@Autowired
private HawkbitSecurityProperties securityProperties;
@@ -93,7 +94,8 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Description("Ensure that the root poll resource is available as CBOR")
void rootPollResourceCbor() throws Exception {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711).accept(DdiRestConstants.MEDIA_TYPE_CBOR))
.andDo(MockMvcResultPrinter.print()).andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR))
.andDo(MockMvcResultPrinter.print())
.andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR))
.andExpect(status().isOk());
}
@@ -101,46 +103,51 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Description("Ensures that the API returns JSON when no Accept header is specified by the client.")
void apiReturnsJSONByDefault() throws Exception {
final MvcResult result = mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON)).andReturn();
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andReturn();
// verify that we did not specify a content-type in the request, in case
// there are any default values
// verify that we did not specify a content-type in the request, in case there are any default values
assertThat(result.getRequest().getHeader("Accept")).isNull();
}
@Test
@Description("Ensures that targets cannot be created e.g. in plug'n play scenarios when tenant does not exists but can be created if the tenant exists.")
@WithUser(tenantId = "tenantDoesNotExists", allSpPermissions = true, authorities = { CONTROLLER_ROLE,
SYSTEM_ROLE }, autoCreateTenant = false)
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@WithUser(tenantId = "tenantDoesNotExists", allSpPermissions = true,
authorities = { CONTROLLER_ROLE, SYSTEM_ROLE }, autoCreateTenant = false)
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1),
@Expect(type = DistributionSetTypeCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleTypeCreatedEvent.class, count = 2) })
void targetCannotBeRegisteredIfTenantDoesNotExistsButWhenExists() throws Exception {
mvc.perform(get("/default-tenant/", tenantAware.getCurrentTenant())).andDo(MockMvcResultPrinter.print())
mvc.perform(get("/default-tenant/", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
// create tenant -- creates softwaremoduletypes and distributionsettypes
// create tenant -- creates software module types and distribution set types
systemManagement.createTenantMetadata("tenantDoesNotExists");
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), "aControllerId"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// delete tenant again, will also deleted target aControllerId
systemManagement.deleteTenant("tenantDoesNotExists");
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), "aControllerId"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
}
@Test
@Description("Ensures that target poll request does not change audit data on the entity.")
@WithUser(principal = "knownPrincipal", authorities = { SpPermission.READ_TARGET, SpPermission.UPDATE_TARGET,
SpPermission.CREATE_TARGET }, allSpPermissions = false)
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
@WithUser(principal = "knownPrincipal", authorities = { SpPermission.READ_TARGET, SpPermission.UPDATE_TARGET, SpPermission.CREATE_TARGET })
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1) })
void targetPollDoesNotModifyAuditData() throws Exception {
// create target first with "knownPrincipal" user and audit data
final String knownTargetControllerId = "target1";
@@ -149,12 +156,12 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
final Target findTargetByControllerID = targetManagement.getByControllerID(knownTargetControllerId).get();
assertThat(findTargetByControllerID.getCreatedBy()).isEqualTo(knownCreatedBy);
// make a poll, audit information should not be changed, run as
// controller principal!
// make a poll, audit information should not be changed, run as controller principal!
SecurityContextSwitch.runAs(SecurityContextSwitch.withController("controller", CONTROLLER_ROLE_ANONYMOUS),
() -> {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownTargetControllerId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
return null;
});
@@ -170,20 +177,25 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Description("Ensures that server returns a not found response in case of empty controller ID.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 0) })
void rootRsWithoutId() throws Exception {
mvc.perform(get("/controller/v1/")).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
mvc.perform(get("/controller/v1/"))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@Test
@Description("Ensures that the system creates a new target in plug and play manner, i.e. target is authenticated but does not exist yet.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1) })
void rootRsPlugAndPlay() throws Exception {
final long current = System.currentTimeMillis();
final String controllerId = "4711";
mvc.perform(get(CONTROLLER_BASE, "default-tenant", controllerId)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaTypes.HAL_JSON))
mvc.perform(get(CONTROLLER_BASE, "default-tenant", controllerId))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")));
assertThat(targetManagement.getByControllerID(controllerId).get().getLastTargetQuery())
.isGreaterThanOrEqualTo(current);
@@ -192,33 +204,38 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
.isEqualTo(TargetUpdateStatus.REGISTERED);
// not allowed methods
mvc.perform(post(CONTROLLER_BASE, "default-tenant", controllerId)).andDo(MockMvcResultPrinter.print())
mvc.perform(post(CONTROLLER_BASE, "default-tenant", controllerId))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(put(CONTROLLER_BASE, "default-tenant", controllerId)).andDo(MockMvcResultPrinter.print())
mvc.perform(put(CONTROLLER_BASE, "default-tenant", controllerId))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(delete(CONTROLLER_BASE, "default-tenant", controllerId)).andDo(MockMvcResultPrinter.print())
mvc.perform(delete(CONTROLLER_BASE, "default-tenant", controllerId))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
}
@Test
@Description("Ensures that tenant specific polling time, which is saved in the db, is delivered to the controller.")
@WithUser(principal = "knownpricipal", allSpPermissions = false)
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void pollWithModifiedGlobalPollingTime() throws Exception {
SecurityContextSwitch.runAs(SecurityContextSwitch.withUser("tenantadmin", TENANT_CONFIGURATION),
() -> {
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
"00:02:00");
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL, "00:02:00");
return null;
});
SecurityContextSwitch.runAs(SecurityContextSwitch.withUser("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaTypes.HAL_JSON))
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:02:00")));
return null;
});
@@ -226,10 +243,12 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Ensures that etag check results in not modified response if provided etag by client is identical to entity in repository.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 6),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 3), @Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 3),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
@Expect(type = DistributionSetUpdatedEvent.class, count = 2), // implicit lock
@@ -239,14 +258,17 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
void rootRsNotModified() throws Exception {
final String controllerId = "4711";
final String etag = mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist())
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))).andReturn().getResponse()
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andReturn().getResponse()
.getHeader("ETag");
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).header("If-None-Match", etag))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotModified());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotModified());
final Target target = targetManagement.getByControllerID(controllerId).get();
final DistributionSet ds = testdataFactory.createDistributionSet("");
@@ -258,7 +280,8 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
final String etagWithFirstUpdate = mvc
.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId)
.header("If-None-Match", etag).accept(MediaType.APPLICATION_JSON).with(new RequestOnHawkbitDefaultPortPostProcessor()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.installedBase.href").doesNotExist())
@@ -270,10 +293,12 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).header("If-None-Match",
etagWithFirstUpdate).with(new RequestOnHawkbitDefaultPortPostProcessor()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotModified());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotModified());
// now lets finish the update
sendDeploymentActionFeedback(target, updateAction, "closed", null).andDo(MockMvcResultPrinter.print())
sendDeploymentActionFeedback(target, updateAction, "closed", null)
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// as the update was installed, and we always receive the installed action, the
@@ -282,7 +307,8 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId)
.header("If-None-Match", etag).accept(MediaType.APPLICATION_JSON)
.with(new RequestOnHawkbitDefaultPortPostProcessor()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist())
@@ -295,13 +321,13 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds2.getId(), controllerId);
final Action updateAction2 = deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId())
.getContent().get(0);
final Action updateAction2 = deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId()).getContent().get(0);
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId)
.header("If-None-Match", etagAfterInstallation).accept(MediaType.APPLICATION_JSON)
.with(new RequestOnHawkbitDefaultPortPostProcessor()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.installedBase.href",
@@ -317,16 +343,16 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
+ "UNKNOWN to REGISTERED when the target polls for the first time.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
void rootRsPrecommissioned() throws Exception {
void rootRsPreCommissioned() throws Exception {
final String controllerId = "4711";
testdataFactory.createTarget(controllerId);
assertThat(targetManagement.getByControllerID(controllerId).get().getUpdateStatus())
.isEqualTo(TargetUpdateStatus.UNKNOWN);
assertThat(targetManagement.getByControllerID(controllerId).get().getUpdateStatus()).isEqualTo(TargetUpdateStatus.UNKNOWN);
final long current = System.currentTimeMillis();
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")));
@@ -341,7 +367,8 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Ensures that the source IP address of the polling target is correctly stored in repository")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1) })
void rootRsPlugAndPlayIpAddress() throws Exception {
// test
@@ -352,7 +379,8 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
SecurityContextSwitch.runAs(SecurityContextSwitch.withController("controller", CONTROLLER_ROLE_ANONYMOUS),
() -> {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownControllerId1))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
return null;
});
@@ -363,12 +391,12 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
assertThat(target.getCreatedAt()).isGreaterThanOrEqualTo(create);
assertThat(target.getLastModifiedBy()).isEqualTo("CONTROLLER_PLUG_AND_PLAY");
assertThat(target.getLastModifiedAt()).isGreaterThanOrEqualTo(create);
}
@Test
@Description("Ensures that the source IP address of the polling target is not stored in repository if disabled")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1) })
void rootRsIpAddressNotStoredIfDisabled() throws Exception {
securityProperties.getClients().setTrackRemoteIp(false);
@@ -376,7 +404,8 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
// test
final String knownControllerId1 = "0815";
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownControllerId1))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// verify
final Target target = targetManagement.getByControllerID(knownControllerId1).get();
@@ -387,13 +416,15 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Controller trys to finish an update process after it has been finished by an error action status.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 2) })
void tryToFinishAnUpdateProcessAfterItHasBeenFinished() throws Exception {
final DistributionSet ds = testdataFactory.createDistributionSet("");
@@ -401,26 +432,32 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
savedTarget = getFirstAssignedTarget(assignDistributionSet(ds.getId(), savedTarget.getControllerId()));
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
sendDeploymentActionFeedback(savedTarget, savedAction, "proceeding", null).andDo(MockMvcResultPrinter.print())
sendDeploymentActionFeedback(savedTarget, savedAction, "proceeding", null)
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
sendDeploymentActionFeedback(savedTarget, savedAction, "closed", "failure").andDo(MockMvcResultPrinter.print())
sendDeploymentActionFeedback(savedTarget, savedAction, "closed", "failure")
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
sendDeploymentActionFeedback(savedTarget, savedAction, "closed", "success").andDo(MockMvcResultPrinter.print())
sendDeploymentActionFeedback(savedTarget, savedAction, "closed", "success")
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isGone());
}
@Test
@Description("Controller sends attribute update request after device successfully closed software update.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
@Expect(type = TargetAssignDistributionSetEvent.class, count = 2),
@Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 6), @Expect(type = TargetPollEvent.class, count = 4),
@Expect(type = ActionCreatedEvent.class, count = 2),
@Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 6),
@Expect(type = TargetPollEvent.class, count = 4),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1) })
void attributeUpdateRequestSendingAfterSuccessfulDeployment() throws Exception {
final DistributionSet ds = testdataFactory.createDistributionSet("1");
@@ -440,13 +477,15 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Test to verify that only a specific count of messages are returned based on the input actionHistory for getControllerDeploymentActionFeedback endpoint.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1) })
void testActionHistoryCount() throws Exception {
@@ -457,17 +496,21 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
.getContent().get(0);
sendDeploymentActionFeedback(savedTarget, savedAction, "scheduled", null, TARGET_SCHEDULED_INSTALLATION_MSG)
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
sendDeploymentActionFeedback(savedTarget, savedAction, "proceeding", null, TARGET_PROCEEDING_INSTALLATION_MSG)
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
sendDeploymentActionFeedback(savedTarget, savedAction, "closed", "success", TARGET_COMPLETED_INSTALLATION_MSG)
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=2", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages",
hasItem(containsString(TARGET_COMPLETED_INSTALLATION_MSG))))
.andExpect(jsonPath("$.actionHistory.messages",
@@ -478,45 +521,52 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Test to verify that a zero input value of actionHistory results in no action history appended for getControllerDeploymentActionFeedback endpoint.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1) })
void testActionHistoryZeroInput() throws Exception {
final DistributionSet ds = testdataFactory.createDistributionSet("");
Target savedTarget = testdataFactory.createTarget("911");
savedTarget = getFirstAssignedTarget(assignDistributionSet(ds.getId(), savedTarget.getControllerId()));
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
sendDeploymentActionFeedback(savedTarget, savedAction, "scheduled", null, TARGET_SCHEDULED_INSTALLATION_MSG)
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
sendDeploymentActionFeedback(savedTarget, savedAction, "proceeding", null, TARGET_PROCEEDING_INSTALLATION_MSG)
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
sendDeploymentActionFeedback(savedTarget, savedAction, "closed", "success", TARGET_COMPLETED_INSTALLATION_MSG)
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=0", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages").doesNotExist());
mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages").doesNotExist());
}
@Test
@Description("Test to verify that entire action history is returned if the input value for actionHistory is -1, for getControllerDeploymentActionFeedback endpoint.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@@ -533,17 +583,21 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
.getContent().get(0);
sendDeploymentActionFeedback(savedTarget, savedAction, "scheduled", null, TARGET_SCHEDULED_INSTALLATION_MSG)
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
sendDeploymentActionFeedback(savedTarget, savedAction, "proceeding", null, TARGET_PROCEEDING_INSTALLATION_MSG)
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
sendDeploymentActionFeedback(savedTarget, savedAction, "closed", "success", TARGET_COMPLETED_INSTALLATION_MSG)
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=-1", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages",
hasItem(containsString(TARGET_SCHEDULED_INSTALLATION_MSG))))
.andExpect(jsonPath("$.actionHistory.messages",
@@ -561,8 +615,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
() -> {
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
"00:05:00");
tenantConfigurationManagement
.addOrUpdateConfiguration(TenantConfigurationKey.MIN_POLLING_TIME_INTERVAL, "00:01:00");
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.MIN_POLLING_TIME_INTERVAL, "00:01:00");
return null;
});
@@ -570,7 +623,8 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
assignDistributionSetWithMaintenanceWindow(ds.getId(), savedTarget.getControllerId(), getTestSchedule(16),
getTestDuration(10), getTestTimeZone()).getAssignedEntity().iterator().next();
mvc.perform(get(CONTROLLER_BASE, "default-tenant", "1911")).andExpect(status().isOk())
mvc.perform(get(CONTROLLER_BASE, "default-tenant", "1911"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.config.polling.sleep", greaterThanOrEqualTo("00:05:00")));
final Target savedTarget1 = testdataFactory.createTarget("2911");
@@ -578,7 +632,8 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
assignDistributionSetWithMaintenanceWindow(ds1.getId(), savedTarget1.getControllerId(), getTestSchedule(10),
getTestDuration(10), getTestTimeZone()).getAssignedEntity().iterator().next();
mvc.perform(get(CONTROLLER_BASE, "default-tenant", "2911")).andExpect(status().isOk())
mvc.perform(get(CONTROLLER_BASE, "default-tenant", "2911"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.config.polling.sleep", lessThan("00:05:00")))
.andExpect(jsonPath("$.config.polling.sleep", greaterThanOrEqualTo("00:03:00")));
@@ -587,7 +642,8 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
assignDistributionSetWithMaintenanceWindow(ds2.getId(), savedTarget2.getControllerId(), getTestSchedule(5),
getTestDuration(5), getTestTimeZone()).getAssignedEntity().iterator().next();
mvc.perform(get(CONTROLLER_BASE, "default-tenant", "3911")).andExpect(status().isOk())
mvc.perform(get(CONTROLLER_BASE, "default-tenant", "3911"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.config.polling.sleep", lessThan("00:02:00")));
final Target savedTarget3 = testdataFactory.createTarget("4911");
@@ -595,9 +651,9 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
assignDistributionSetWithMaintenanceWindow(ds3.getId(), savedTarget3.getControllerId(), getTestSchedule(-5),
getTestDuration(15), getTestTimeZone()).getAssignedEntity().iterator().next();
mvc.perform(get(CONTROLLER_BASE, "default-tenant", "4911")).andExpect(status().isOk())
mvc.perform(get(CONTROLLER_BASE, "default-tenant", "4911"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:05:00")));
}
@Test
@@ -608,13 +664,15 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
savedTarget = getFirstAssignedTarget(assignDistributionSetWithMaintenanceWindow(ds.getId(),
savedTarget.getControllerId(), getTestSchedule(2), getTestDuration(1), getTestTimeZone()));
mvc.perform(get(CONTROLLER_BASE, "default-tenant", "1911")).andExpect(status().isOk());
mvc.perform(get(CONTROLLER_BASE, "default-tenant", "1911"))
.andExpect(status().isOk());
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "1911", action.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.deployment.download", equalTo("forced")))
.andExpect(jsonPath("$.deployment.update", equalTo("skip")))
.andExpect(jsonPath("$.deployment.maintenanceWindow", equalTo("unavailable")));
@@ -628,13 +686,15 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
savedTarget = getFirstAssignedTarget(assignDistributionSetWithMaintenanceWindow(ds.getId(),
savedTarget.getControllerId(), getTestSchedule(-5), getTestDuration(10), getTestTimeZone()));
mvc.perform(get(CONTROLLER_BASE, "default-tenant", "1911")).andExpect(status().isOk());
mvc.perform(get(CONTROLLER_BASE, "default-tenant", "1911"))
.andExpect(status().isOk());
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0);
mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "1911", action.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.deployment.download", equalTo("forced")))
.andExpect(jsonPath("$.deployment.update", equalTo("forced")))
.andExpect(jsonPath("$.deployment.maintenanceWindow", equalTo("available")));
@@ -648,13 +708,11 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
final DistributionSet ds1 = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
final DistributionSet ds2 = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
final Action action1 = getFirstAssignedAction(assignDistributionSet(ds1.getId(), target.getControllerId(), 56));
final Long action2Id = getFirstAssignedActionId(
assignDistributionSet(ds2.getId(), target.getControllerId(), 34));
final Long action2Id = getFirstAssignedActionId(assignDistributionSet(ds2.getId(), target.getControllerId(), 34));
assertDeploymentActionIsExposedToTarget(target.getControllerId(), action1.getId());
sendDeploymentActionFeedback(target, action1, "closed", "success");
assertDeploymentActionIsExposedToTarget(target.getControllerId(), action2Id);
}
@Test
@@ -666,39 +724,39 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
}
@Step
private void assertAttributesUpdateNotRequestedAfterFailedDeployment(Target target, final DistributionSet ds)
throws Exception {
private void assertAttributesUpdateNotRequestedAfterFailedDeployment(Target target, final DistributionSet ds) throws Exception {
target = getFirstAssignedTarget(assignDistributionSet(ds.getId(), target.getControllerId()));
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId())
.getContent().get(0);
sendDeploymentActionFeedback(target, action, "closed", "failure").andExpect(status().isOk());
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId()).getContent().get(0);
sendDeploymentActionFeedback(target, action, "closed", "failure")
.andExpect(status().isOk());
assertThatAttributesUpdateIsNotRequested(target.getControllerId());
}
@Step
private void assertAttributesUpdateRequestedAfterSuccessfulDeployment(Target target, final DistributionSet ds)
throws Exception {
private void assertAttributesUpdateRequestedAfterSuccessfulDeployment(Target target, final DistributionSet ds) throws Exception {
target = getFirstAssignedTarget(assignDistributionSet(ds.getId(), target.getControllerId()));
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId())
.getContent().get(0);
sendDeploymentActionFeedback(target, action, "closed", null).andExpect(status().isOk());
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId()).getContent().get(0);
sendDeploymentActionFeedback(target, action, "closed", null)
.andExpect(status().isOk());
assertThatAttributesUpdateIsRequested(target.getControllerId());
}
private void assertThatAttributesUpdateIsRequested(final String targetControllerId) throws Exception {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), targetControllerId)
.accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.configData.href").isNotEmpty());
}
private void assertThatAttributesUpdateIsNotRequested(final String targetControllerId) throws Exception {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), targetControllerId)
.accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.configData").doesNotExist());
}
private ResultActions sendDeploymentActionFeedback(final Target target, final Action action, final String execution,
String finished, String message) throws Exception {
private ResultActions sendDeploymentActionFeedback(final Target target, final Action action, final String execution, String finished,
String message) throws Exception {
if (finished == null) {
finished = "none";
}
@@ -713,19 +771,18 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
.content(feedback).contentType(MediaType.APPLICATION_JSON));
}
private ResultActions sendDeploymentActionFeedback(final Target target, final Action action, final String execution,
final String finished) throws Exception {
private ResultActions sendDeploymentActionFeedback(final Target target, final Action action, final String execution, final String finished)
throws Exception {
return sendDeploymentActionFeedback(target, action, execution, finished, null);
}
private void assertDeploymentActionIsExposedToTarget(final String controllerId, final long expectedActionId)
throws Exception {
private void assertDeploymentActionIsExposedToTarget(final String controllerId, final long expectedActionId) throws Exception {
final String expectedDeploymentBaseLink = String.format("/%s/controller/v1/%s/deploymentBase/%d",
tenantAware.getCurrentTenant(), controllerId, expectedActionId);
mvc.perform(
get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.deploymentBase.href", containsString(expectedDeploymentBaseLink)));
}
}
}

View File

@@ -46,28 +46,26 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest {
@Override
protected DefaultMockMvcBuilder createMvcWebAppContext(final WebApplicationContext context) {
return super.createMvcWebAppContext(context).addFilter(
new DosFilter(null, 10, 10,
"127\\.0\\.0\\.1|\\[0:0:0:0:0:0:0:1\\]", "(^192\\.168\\.)",
"X-Forwarded-For"));
new DosFilter(null, 10, 10, "127\\.0\\.0\\.1|\\[0:0:0:0:0:0:0:1\\]", "(^192\\.168\\.)", "X-Forwarded-For"));
}
@Test
@Description("Ensures that clients that are on the blacklist are forbidden")
void blackListedClientIsForbidden() throws Exception {
mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant())
.header(X_FORWARDED_FOR, "192.168.0.4 , 10.0.0.1 ")).andExpect(status().isForbidden());
.header(X_FORWARDED_FOR, "192.168.0.4 , 10.0.0.1 "))
.andExpect(status().isForbidden());
}
@Test
@Description("Ensures that a READ DoS attempt is blocked ")
void getFloodingAttackThatIsPrevented() throws Exception {
MvcResult result = null;
int requests = 0;
MvcResult result;
do {
result = mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant())
.header(X_FORWARDED_FOR, "10.0.0.1")).andReturn();
.header(X_FORWARDED_FOR, "10.0.0.1"))
.andReturn();
requests++;
// we give up after 1.000 requests
@@ -83,7 +81,8 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest {
void unacceptableGetLoadButOnWhitelistIPv4() throws Exception {
for (int i = 0; i < 100; i++) {
mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant())
.header(X_FORWARDED_FOR, "127.0.0.1")).andExpect(status().isOk());
.header(X_FORWARDED_FOR, "127.0.0.1"))
.andExpect(status().isOk());
}
}
@@ -92,22 +91,23 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest {
void unacceptableGetLoadButOnWhitelistIPv6() throws Exception {
for (int i = 0; i < 100; i++) {
mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant())
.header(X_FORWARDED_FOR, "0:0:0:0:0:0:0:1")).andExpect(status().isOk());
.header(X_FORWARDED_FOR, "0:0:0:0:0:0:0:1"))
.andExpect(status().isOk());
}
}
@Test
@Description("Ensures that a relatively high number of READ requests is allowed if it is below the DoS detection threshold")
// No idea how to get rid of the Thread.sleep here
@SuppressWarnings("squid:S2925")
// No idea how to get rid of the Thread.sleep here
void acceptableGetLoad() throws Exception {
for (int x = 0; x < 3; x++) {
// sleep for one second
Thread.sleep(1100);
for (int i = 0; i < 9; i++) {
mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant())
.header(X_FORWARDED_FOR, "10.0.0.1")).andExpect(status().isOk());
.header(X_FORWARDED_FOR, "10.0.0.1"))
.andExpect(status().isOk());
}
}
}
@@ -118,8 +118,8 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest {
final Long actionId = prepareDeploymentBase();
final String feedback = getJsonProceedingDeploymentActionFeedback();
MvcResult result = null;
int requests = 0;
MvcResult result;
do {
result = mvc.perform(post("/{tenant}/controller/v1/4711/deploymentBase/" + actionId + "/feedback",
tenantAware.getCurrentTenant()).header(X_FORWARDED_FOR, "10.0.0.1").content(feedback)
@@ -133,13 +133,12 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest {
// the filter shuts down after 10 POST requests
assertThat(requests).isGreaterThanOrEqualTo(10);
}
@Test
@Description("Ensures that a relatively high number of WRITE requests is allowed if it is below the DoS detection threshold")
// No idea how to get rid of the Thread.sleep here
@SuppressWarnings("squid:S2925")
// No idea how to get rid of the Thread.sleep here
void acceptablePutPostLoad() throws Exception {
final Long actionId = prepareDeploymentBase();
final String feedback = getJsonProceedingDeploymentActionFeedback();
@@ -166,8 +165,7 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds, toAssign);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId())).hasSize(1);
final Action uaction = deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId())
.getContent().get(0);
final Action uaction = deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId()).getContent().get(0);
return uaction.getId();
}