Prioritisation of assignments via mgmt-API (#895)

* Updating the schema for targetfilterquery and rollout
* Updating the weight validation logic and tests
* Make weight optional
* Fix existing multi assignment tests by adding weight, remove weight from TargetFilterQuery
* Add weight validation tests, fix tests
* Add mgmt api tests for assignment and getting action with weight
* Add management layer validation and tests for creating rollouts with weight
* Fix amqp test, add repo level validation to resource tests
* Add weight to rollout mgmt-api and tests
* Add weight to mgmt api target Filter create and update
* Add target filter auto assign weight. disable enforcement of setting a weight in multiassign mode
* Remove ignored tests, fix api doc
* Fix minor findings
* Fix findings
* Remove hardcoded min weight
* Add docu text, fix findings
* Fix api documentation
* Expose weight via DMF
* Expose actions according to weight via ddi
* Fix documentation
* Add method to get actions ordered by weight to deploymentManagement
* Updating the schema for targetfilterquery and rollout
* Updated the indentation
* Updated the helper class, fixed the randomUID in test factory
* Updated the class name with prefix JPA
* Adding the missing License for WeightValidationHelper class
* Adding documentation to the dmf api on weight
* Removed the merger markers
* Updated the class name
* Removed the redundant method
* Addressed final PR comments
* Updated the missing testcase with latest default weight value
* Reverting the default value of weight back to 1000 and updated tests

Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com>
Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>
This commit is contained in:
Stefan Klotz
2019-11-08 10:47:35 +01:00
committed by Stefan Behl
parent 09f2d8a481
commit 9cb5d31396
98 changed files with 2425 additions and 875 deletions

View File

@@ -149,7 +149,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
final Action action = controllerManagement.findOldestActiveActionByTarget(controllerId).orElse(null);
final Action action = controllerManagement.findActiveActionWithHighestWeight(controllerId).orElse(null);
checkAndCancelExpiredAction(action);

View File

@@ -105,12 +105,12 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@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)})
@Expect(type = SoftwareModuleTypeCreatedEvent.class, count = 2) })
public void targetCannotBeRegisteredIfTenantDoesNotExistsButWhenExists() throws Exception {
mvc.perform(get("/default-tenant/", tenantAware.getCurrentTenant())).andDo(MockMvcResultPrinter.print())
@@ -131,10 +131,10 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@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 }, allSpPermissions = false)
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
public void targetPollDoesNotModifyAuditData() throws Exception {
// create target first with "knownPrincipal" user and audit data
final String knownTargetControllerId = "target1";
@@ -162,15 +162,15 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Ensures that server returns a not found response in case of empty controlloer ID.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 0)})
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 0) })
public void rootRsWithoutId() throws Exception {
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),
@Expect(type = TargetPollEvent.class, count = 1)})
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1) })
public void rootRsPlugAndPlay() throws Exception {
final long current = System.currentTimeMillis();
@@ -198,8 +198,8 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@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),
@Expect(type = TargetPollEvent.class, count = 1)})
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1) })
public void pollWithModifiedGloablPollingTime() throws Exception {
securityRule.runAs(WithSpringAuthorityRule.withUser("tenantadmin", HAS_AUTH_TENANT_CONFIGURATION), () -> {
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
@@ -218,14 +218,14 @@ public 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 = DistributionSetCreatedEvent.class, count = 2),
@Expect(type = ActionCreatedEvent.class, count = 2),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6)})
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6) })
public void rootRsNotModified() throws Exception {
final String etag = mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -289,8 +289,8 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Ensures that the target state machine of a precomissioned target switches from "
+ "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)})
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
public void rootRsPrecommissioned() throws Exception {
testdataFactory.createTarget("4711");
@@ -314,8 +314,8 @@ public 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),
@Expect(type = TargetPollEvent.class, count = 1)})
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1) })
public void rootRsPlugAndPlayIpAddress() throws Exception {
// test
final String knownControllerId1 = "0815";
@@ -341,8 +341,8 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@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),
@Expect(type = TargetPollEvent.class, count = 1)})
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1) })
public void rootRsIpAddressNotStoredIfDisabled() throws Exception {
securityProperties.getClients().setTrackRemoteIp(false);
@@ -360,12 +360,12 @@ public 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 = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3)})
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3) })
public void tryToFinishAnUpdateProcessAfterItHasBeenFinished() throws Exception {
final DistributionSet ds = testdataFactory.createDistributionSet("");
Target savedTarget = testdataFactory.createTarget("911");
@@ -384,13 +384,13 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@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 = 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 = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1)})
@Expect(type = TargetAttributesRequestedEvent.class, count = 1) })
public void attributeUpdateRequestSendingAfterSuccessfulDeployment() throws Exception {
final DistributionSet ds = testdataFactory.createDistributionSet("1");
final Target savedTarget = testdataFactory.createTarget("922");
@@ -463,13 +463,13 @@ public 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 = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3)})
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3) })
public void testActionHistoryCount() throws Exception {
final DistributionSet ds = testdataFactory.createDistributionSet("");
Target savedTarget = testdataFactory.createTarget("911");
@@ -498,13 +498,13 @@ public 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 = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3)})
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3) })
public void testActionHistoryZeroInput() throws Exception {
final DistributionSet ds = testdataFactory.createDistributionSet("");
Target savedTarget = testdataFactory.createTarget("911");
@@ -529,13 +529,13 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@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 = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3)})
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3) })
public void testActionHistoryNegativeInput() throws Exception {
final DistributionSet ds = testdataFactory.createDistributionSet("");
Target savedTarget = testdataFactory.createTarget("911");
@@ -654,12 +654,13 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Assign multiple DS in multi-assignment mode. The earliest active Action is exposed to the controller.")
public void earliestActionIsExposedToControllerInMultiAssignMode() throws Exception {
setMultiAssignmentsEnabled();
enableMultiAssignments();
final Target target = testdataFactory.createTarget();
final DistributionSet ds1 = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
final DistributionSet ds2 = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
final Action action1 = getFirstAssignedAction(assignDistributionSet(ds1, target));
final Long action2Id = getFirstAssignedActionId(assignDistributionSet(ds2, target));
final Action action1 = getFirstAssignedAction(assignDistributionSet(ds1.getId(), target.getControllerId(), 56));
final Long action2Id = getFirstAssignedActionId(
assignDistributionSet(ds2.getId(), target.getControllerId(), 34));
assertDeploymentActionIsExposedToTarget(target.getControllerId(), action1.getId());
sendDeploymentActionFeedback(target, action1, "closed", "success");
@@ -670,7 +671,7 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("The system should not create a new target because of a too long controller id.")
public void rootRsWithInvalidControllerId() throws Exception {
String invalidControllerId = RandomStringUtils.randomAlphabetic(Target.CONTROLLER_ID_MAX_SIZE + 1);
final String invalidControllerId = RandomStringUtils.randomAlphabetic(Target.CONTROLLER_ID_MAX_SIZE + 1);
mvc.perform(get("/{tenant}/controller/v1/{controllerId}", tenantAware.getCurrentTenant(), invalidControllerId))
.andExpect(status().isBadRequest());
}
@@ -684,8 +685,4 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
.andExpect(jsonPath("$._links.deploymentBase.href", containsString(expectedDeploymentBaseLink)));
}
private void setMultiAssignmentsEnabled() {
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, true);
}
}

View File

@@ -57,9 +57,12 @@ public class MgmtAction extends MgmtBaseEntity {
@JsonProperty
private Long forceTime;
@JsonProperty(value="forceType")
@JsonProperty(value = "forceType")
private MgmtActionType actionType;
@JsonProperty
private Integer weight;
@JsonProperty
private MgmtMaintenanceWindow maintenanceWindow;
@@ -79,6 +82,14 @@ public class MgmtAction extends MgmtBaseEntity {
this.forceTime = forceTime;
}
public Integer getWeight() {
return weight;
}
public void setWeight(final Integer weight) {
this.weight = weight;
}
public MgmtActionType getActionType() {
return actionType;
}
@@ -110,5 +121,4 @@ public class MgmtAction extends MgmtBaseEntity {
public void setType(final String type) {
this.type = type;
}
}

View File

@@ -25,6 +25,7 @@ public class MgmtTargetAssignmentRequestBody {
private long forcetime;
private MgmtActionType type;
private MgmtMaintenanceWindowRequestBody maintenanceWindow;
private Integer weight;
/**
* JsonCreator Constructor
@@ -61,6 +62,14 @@ public class MgmtTargetAssignmentRequestBody {
this.forcetime = forcetime;
}
public Integer getWeight() {
return weight;
}
public void setWeight(final Integer weight) {
this.weight = weight;
}
public MgmtMaintenanceWindowRequestBody getMaintenanceWindow() {
return maintenanceWindow;
}
@@ -68,5 +77,4 @@ public class MgmtTargetAssignmentRequestBody {
public void setMaintenanceWindow(final MgmtMaintenanceWindowRequestBody maintenanceWindow) {
this.maintenanceWindow = maintenanceWindow;
}
}

View File

@@ -12,12 +12,12 @@ import java.util.HashMap;
import java.util.Map;
import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
/**
*
@@ -47,6 +47,9 @@ public class MgmtRolloutResponseBody extends MgmtNamedEntity {
@JsonProperty
private MgmtActionType type;
@JsonProperty
private Integer weight;
public boolean isDeleted() {
return deleted;
}
@@ -114,4 +117,12 @@ public class MgmtRolloutResponseBody extends MgmtNamedEntity {
public MgmtActionType getType() {
return type;
}
public void setWeight(final Integer weight) {
this.weight = weight;
}
public Integer getWeight() {
return weight;
}
}

View File

@@ -16,6 +16,7 @@ import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroup;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Model for request containing a rollout body e.g. in a POST request of
@@ -34,6 +35,9 @@ public class MgmtRolloutRestRequestBody extends AbstractMgmtRolloutConditionsEnt
private Long startAt;
@JsonProperty(required = false)
private Integer weight;
private MgmtActionType type;
private List<MgmtRolloutGroup> groups;
@@ -124,7 +128,7 @@ public class MgmtRolloutRestRequestBody extends AbstractMgmtRolloutConditionsEnt
* @param groups
* List of {@link MgmtRolloutGroup}
*/
public void setGroups(List<MgmtRolloutGroup> groups) {
public void setGroups(final List<MgmtRolloutGroup> groups) {
this.groups = groups;
}
@@ -139,7 +143,22 @@ public class MgmtRolloutRestRequestBody extends AbstractMgmtRolloutConditionsEnt
* @param startAt
* the start at timestamp in millis or null
*/
public void setStartAt(Long startAt) {
public void setStartAt(final Long startAt) {
this.startAt = startAt;
}
/**
* @return the priority of {@link Rollout}
*/
public Integer getWeight() {
return weight;
}
/**
* @param weight
* the priority of {@link Rollout}
*/
public void setWeight(final Integer weight) {
this.weight = weight;
}
}

View File

@@ -17,6 +17,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class MgmtDistributionSetAssignment extends MgmtId {
private long forcetime;
@JsonProperty(required = false)
private Integer weight;
private MgmtActionType type;
private MgmtMaintenanceWindowRequestBody maintenanceWindow;
@@ -47,6 +49,14 @@ public class MgmtDistributionSetAssignment extends MgmtId {
this.forcetime = forcetime;
}
public Integer getWeight() {
return weight;
}
public void setWeight(final int weight) {
this.weight = weight;
}
/**
* Returns {@link MgmtMaintenanceWindowRequestBody} for distribution set
* assignment.

View File

@@ -22,6 +22,9 @@ public class MgmtDistributionSetAutoAssignment extends MgmtId {
@JsonProperty(required = false)
private MgmtActionType type;
@JsonProperty(required = false)
private Integer weight;
public MgmtActionType getType() {
return type;
}
@@ -29,4 +32,12 @@ public class MgmtDistributionSetAutoAssignment extends MgmtId {
public void setType(final MgmtActionType type) {
this.type = type;
}
public Integer getWeight() {
return weight;
}
public void setWeight(final Integer weight) {
this.weight = weight;
}
}

View File

@@ -40,6 +40,9 @@ public class MgmtTargetFilterQuery extends MgmtBaseEntity {
@JsonProperty
private MgmtActionType autoAssignActionType;
@JsonProperty
private Integer autoAssignWeight;
public Long getFilterId() {
return filterId;
}
@@ -80,4 +83,11 @@ public class MgmtTargetFilterQuery extends MgmtBaseEntity {
this.autoAssignActionType = actionType;
}
public Integer getAutoAssignWeight() {
return autoAssignWeight;
}
public void setAutoAssignWeight(final Integer autoAssignWeight) {
this.autoAssignWeight = autoAssignWeight;
}
}

View File

@@ -33,8 +33,7 @@ public class MgmtTargetFilterQueryRequestBody {
return query;
}
public void setQuery(String query) {
public void setQuery(final String query) {
this.query = query;
}
}

View File

@@ -38,7 +38,7 @@ public final class MgmtDeploymentRequestMapper {
final String targetId) {
return createAssignmentRequest(targetId, dsAssignment.getId(), dsAssignment.getType(),
dsAssignment.getForcetime(), dsAssignment.getMaintenanceWindow());
dsAssignment.getForcetime(), dsAssignment.getWeight(), dsAssignment.getMaintenanceWindow());
}
/**
@@ -54,13 +54,14 @@ public final class MgmtDeploymentRequestMapper {
final Long dsId) {
return createAssignmentRequest(targetAssignment.getId(), dsId, targetAssignment.getType(),
targetAssignment.getForcetime(), targetAssignment.getMaintenanceWindow());
targetAssignment.getForcetime(), targetAssignment.getWeight(), targetAssignment.getMaintenanceWindow());
}
private static DeploymentRequest createAssignmentRequest(final String targetId, final Long dsId,
final MgmtActionType type, final long forcetime, final MgmtMaintenanceWindowRequestBody maintenanceWindow) {
final MgmtActionType type, final long forcetime, final Integer weight,
final MgmtMaintenanceWindowRequestBody maintenanceWindow) {
final DeploymentRequestBuilder request = DeploymentManagement.deploymentRequest(targetId, dsId)
.setActionType(MgmtRestModelMapper.convertActionType(type)).setForceTime(forcetime);
.setActionType(MgmtRestModelMapper.convertActionType(type)).setForceTime(forcetime).setWeight(weight);
if (maintenanceWindow != null) {
final String cronSchedule = maintenanceWindow.getSchedule();
final String duration = maintenanceWindow.getDuration();
@@ -70,5 +71,4 @@ public final class MgmtDeploymentRequestMapper {
}
return request.build();
}
}

View File

@@ -266,7 +266,6 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
final List<DistributionSetAssignmentResult> assignmentResults = deployManagament
.assignDistributionSets(deploymentRequests);
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponse(assignmentResults));
}
@Override

View File

@@ -79,6 +79,7 @@ final class MgmtRolloutMapper {
body.setTotalTargets(rollout.getTotalTargets());
body.setDeleted(rollout.isDeleted());
body.setType(MgmtRestModelMapper.convertActionType(rollout.getActionType()));
rollout.getWeight().ifPresent(body::setWeight);
if (withDetails) {
for (final TotalTargetCountStatus.Status status : TotalTargetCountStatus.Status.values()) {
@@ -106,7 +107,8 @@ final class MgmtRolloutMapper {
return entityFactory.rollout().create().name(restRequest.getName()).description(restRequest.getDescription())
.set(distributionSet).targetFilterQuery(restRequest.getTargetFilterQuery())
.actionType(MgmtRestModelMapper.convertActionType(restRequest.getType()))
.forcedTime(restRequest.getForcetime()).startAt(restRequest.getStartAt());
.forcedTime(restRequest.getForcetime()).startAt(restRequest.getStartAt())
.weight(restRequest.getWeight());
}
static RolloutGroupCreate fromRequest(final EntityFactory entityFactory, final MgmtRolloutGroup restRequest) {
@@ -249,5 +251,4 @@ final class MgmtRolloutMapper {
private static String createIllegalArgumentLiteral(final Condition condition) {
return "Condition " + condition + NOT_SUPPORTED;
}
}

View File

@@ -15,11 +15,14 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtDistributionSetAutoAssignment;
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQuery;
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQueryRequestBody;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetFilterQueryRestApi;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.springframework.util.CollectionUtils;
@@ -58,6 +61,7 @@ public final class MgmtTargetFilterQueryMapper {
if (distributionSet != null) {
targetRest.setAutoAssignDistributionSet(distributionSet.getId());
targetRest.setAutoAssignActionType(MgmtRestModelMapper.convertActionType(filter.getAutoAssignActionType()));
filter.getAutoAssignWeight().ifPresent(targetRest::setAutoAssignWeight);
}
targetRest.add(linkTo(methodOn(MgmtTargetFilterQueryRestApi.class).getFilter(filter.getId())).withSelfRel());
@@ -76,4 +80,12 @@ public final class MgmtTargetFilterQueryMapper {
return entityFactory.targetFilterQuery().create().name(filterRest.getName()).query(filterRest.getQuery());
}
static AutoAssignDistributionSetUpdate fromRequest(final EntityFactory entityFactory, final long filterId,
final MgmtDistributionSetAutoAssignment assignRest) {
final ActionType type = MgmtRestModelMapper.convertActionType(assignRest.getType());
return entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(assignRest.getId()).actionType(type)
.weight(assignRest.getWeight());
}
}

View File

@@ -108,8 +108,9 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA
@RequestBody final MgmtTargetFilterQueryRequestBody targetFilterRest) {
LOG.debug("updating target filter query {}", filterId);
final TargetFilterQuery updateFilter = filterManagement.update(entityFactory.targetFilterQuery()
.update(filterId).name(targetFilterRest.getName()).query(targetFilterRest.getQuery()));
final TargetFilterQuery updateFilter = filterManagement
.update(entityFactory.targetFilterQuery().update(filterId).name(targetFilterRest.getName())
.query(targetFilterRest.getQuery()));
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(updateFilter);
MgmtTargetFilterQueryMapper.addLinks(response);
@@ -127,10 +128,10 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA
@Override
public ResponseEntity<MgmtTargetFilterQuery> postAssignedDistributionSet(
@PathVariable("filterId") final Long filterId,
@RequestBody final MgmtDistributionSetAutoAssignment dsIdWithActionType) {
@RequestBody final MgmtDistributionSetAutoAssignment autoAssignRequest) {
final TargetFilterQuery updateFilter = filterManagement.updateAutoAssignDSWithActionType(filterId,
dsIdWithActionType.getId(), MgmtRestModelMapper.convertActionType(dsIdWithActionType.getType()));
final TargetFilterQuery updateFilter = filterManagement.updateAutoAssignDS(
MgmtTargetFilterQueryMapper.fromRequest(entityFactory, filterId, autoAssignRequest));
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(updateFilter);
MgmtTargetFilterQueryMapper.addLinks(response);
@@ -156,7 +157,7 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA
@Override
public ResponseEntity<Void> deleteAssignedDistributionSet(@PathVariable("filterId") final Long filterId) {
filterManagement.updateAutoAssignDS(filterId, null);
filterManagement.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(null));
return ResponseEntity.noContent().build();
}

View File

@@ -206,6 +206,7 @@ public final class MgmtTargetMapper {
if (ActionType.TIMEFORCED == action.getActionType()) {
result.setForceTime(action.getForcedTime());
}
action.getWeight().ifPresent(result::setWeight);
result.setActionType(MgmtRestModelMapper.convertActionType(action.getActionType()));
if (action.isActive()) {
@@ -289,5 +290,4 @@ public final class MgmtTargetMapper {
static List<MgmtMetadata> toResponseTargetMetadata(final List<TargetMetadata> metadata) {
return metadata.stream().map(MgmtTargetMapper::toResponseTargetMetadata).collect(Collectors.toList());
}
}

View File

@@ -12,6 +12,7 @@ import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.NamedEntity;
@@ -21,6 +22,8 @@ import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.test.TestConfiguration;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
import org.eclipse.hawkbit.rest.RestConfiguration;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
@@ -197,4 +200,24 @@ public abstract class AbstractManagementApiIntegrationTest extends AbstractRestI
};
}
protected static JSONObject getAssignmentObject(final Object id, final MgmtActionType type) {
final JSONObject obj = new JSONObject();
try {
obj.put("id", id);
obj.put("type", type.getName());
} catch (final JSONException e) {
e.printStackTrace();
}
return obj;
}
protected static JSONObject getAssignmentObject(final Object id, final MgmtActionType type, final int weight) {
try {
return getAssignmentObject(id, type).put("weight", weight);
} catch (final JSONException e) {
e.printStackTrace();
}
return new JSONObject();
}
}

View File

@@ -555,9 +555,8 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
final Set<DistributionSet> createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1);
final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next();
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name(knownFilterName).query("name==y")).getId(),
createdDs.getId());
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name(knownFilterName)
.query("name==y").autoAssignDistributionSet(createdDs.getId()));
// create some dummy target filter queries
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("b").query("name==y"));
@@ -615,12 +614,10 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
private void prepareTestFilters(final String filterNamePrefix, final DistributionSet createdDs) {
// create target filter queries that should be found
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name(filterNamePrefix + "1").query("name==y"))
.getId(), createdDs.getId());
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name(filterNamePrefix + "2").query("name==y"))
.getId(), createdDs.getId());
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name(filterNamePrefix + "1")
.query("name==y").autoAssignDistributionSet(createdDs.getId()));
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name(filterNamePrefix + "2")
.query("name==y").autoAssignDistributionSet(createdDs.getId()));
// create some dummy target filter queries
targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name(filterNamePrefix + "b").query("name==y"));
@@ -1247,8 +1244,8 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
}
@Test
@Description("Ensures that multi target assignment through API is reflected by the repository in the case of " +
"DOWNLOAD_ONLY.")
@Description("Ensures that multi target assignment through API is reflected by the repository in the case of "
+ "DOWNLOAD_ONLY.")
public void assignMultipleTargetsToDistributionSetAsDownloadOnly() throws Exception {
final DistributionSet createdDs = testdataFactory.createDistributionSet();
@@ -1263,8 +1260,8 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
assignDistributionSet(createdDs.getId(), knownTargetIds[0], Action.ActionType.DOWNLOAD_ONLY);
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", createdDs.getId())
.contentType(MediaType.APPLICATION_JSON).content(list.toString()))
.andExpect(status().isOk()).andExpect(jsonPath("$.assigned", equalTo(knownTargetIds.length - 1)))
.contentType(MediaType.APPLICATION_JSON).content(list.toString())).andExpect(status().isOk())
.andExpect(jsonPath("$.assigned", equalTo(knownTargetIds.length - 1)))
.andExpect(jsonPath("$.alreadyAssigned", equalTo(1)))
.andExpect(jsonPath("$.total", equalTo(knownTargetIds.length)));
@@ -1310,10 +1307,10 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
final Long dsId = testdataFactory.createDistributionSet().getId();
final JSONArray body = new JSONArray();
body.put(getAssignmentObject(targetIds.get(0), MgmtActionType.FORCED));
body.put(getAssignmentObject(targetIds.get(0), MgmtActionType.FORCED));
body.put(getAssignmentObject(targetIds.get(1), MgmtActionType.FORCED));
body.put(getAssignmentObject(targetIds.get(1), MgmtActionType.SOFT));
body.put(getAssignmentObject(targetIds.get(0), MgmtActionType.FORCED, 56));
body.put(getAssignmentObject(targetIds.get(0), MgmtActionType.FORCED, 78));
body.put(getAssignmentObject(targetIds.get(1), MgmtActionType.FORCED, 67));
body.put(getAssignmentObject(targetIds.get(1), MgmtActionType.SOFT, 34));
enableMultiAssignments();
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", dsId).content(body.toString())
@@ -1321,14 +1318,32 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
.andExpect(jsonPath("total", equalTo(body.length())));
}
@Test
@Description("An assignment request containing a weight is only accepted when weight is valide and multi assignment is on.")
public void weightValidation() throws Exception {
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final int weight = 78;
final JSONArray bodyValide = new JSONArray().put(getAssignmentObject(targetId, MgmtActionType.FORCED, weight));
final JSONArray bodyInvalide = new JSONArray()
.put(getAssignmentObject(targetId, MgmtActionType.FORCED, Action.WEIGHT_MIN - 1));
public static JSONObject getAssignmentObject(final String targetId, final MgmtActionType type)
throws JSONException {
final JSONObject obj = new JSONObject();
obj.put("id", targetId);
obj.put("type", type.getName());
return obj;
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", dsId).content(bodyValide.toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.multiassignmentNotEnabled")));
enableMultiAssignments();
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", dsId).content(bodyInvalide.toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.repo.constraintViolation")));
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", dsId).content(bodyValide.toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).get().collect(Collectors.toList());
assertThat(actions).size().isEqualTo(1);
assertThat(actions.get(0).getWeight()).get().isEqualTo(weight);
}
}

View File

@@ -916,6 +916,36 @@ public class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTes
postRollout("rollout1", 10, dsA.getId(), "id==target*", 20, Action.ActionType.DOWNLOAD_ONLY);
}
@Test
@Description("A rollout create request containing a weight is only accepted when weight is valide and multi assignment is on.")
public void weightValidation() throws Exception {
testdataFactory.createTargets(4, "rollout", "description");
final Long dsId = testdataFactory.createDistributionSet().getId();
final int weight = 66;
final String invalideWeightRequest = JsonBuilder.rollout("withWeight", "d", 2, dsId, "id==rollout*",
new RolloutGroupConditionBuilder().withDefaults().build(), null, null, Action.WEIGHT_MIN - 1);
final String valideWeightRequest = JsonBuilder.rollout("withWeight", "d", 2, dsId, "id==rollout*",
new RolloutGroupConditionBuilder().withDefaults().build(), null, null, weight);
mvc.perform(post("/rest/v1/rollouts").content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.multiassignmentNotEnabled")));
enableMultiAssignments();
mvc.perform(post("/rest/v1/rollouts").content(invalideWeightRequest).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.repo.constraintViolation")));
mvc.perform(post("/rest/v1/rollouts").content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isCreated());
final List<Rollout> rollouts = rolloutManagement.findAll(PAGE, false).getContent();
assertThat(rollouts).hasSize(1);
assertThat(rollouts.get(0).getWeight()).get().isEqualTo(weight);
}
protected <T> T doWithTimeout(final Callable<T> callable, final SuccessCondition<T> successCondition,
final long timeout, final long pollInterval) throws Exception // NOPMD
{
@@ -955,14 +985,12 @@ public class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTes
private void postRollout(final String name, final int groupSize, final Long distributionSetId,
final String targetFilterQuery, final int targets, final Action.ActionType type) throws Exception {
String actionType = MgmtRestModelMapper.convertActionType(type).getName();
String rollout = JsonBuilder.rollout(name, "desc", groupSize, distributionSetId, targetFilterQuery,
new RolloutGroupConditionBuilder().withDefaults().build(), null, actionType);
final String actionType = MgmtRestModelMapper.convertActionType(type).getName();
final String rollout = JsonBuilder.rollout(name, "desc", groupSize, distributionSetId, targetFilterQuery,
new RolloutGroupConditionBuilder().withDefaults().build(), null, actionType, null);
mvc.perform(post("/rest/v1/rollouts")
.content(rollout)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
mvc.perform(post("/rest/v1/rollouts").content(rollout).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(jsonPath("$.name", equalTo(name))).andExpect(jsonPath("$.status", equalTo("creating")))
.andExpect(jsonPath("$.type", equalTo(actionType)))
.andExpect(jsonPath("$.targetFilterQuery", equalTo(targetFilterQuery)))

View File

@@ -20,12 +20,15 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.List;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException;
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignDistributionSetException;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
@@ -104,8 +107,7 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
public void updateTargetWhichDoesNotExistsLeadsToEntityNotFound() throws Exception {
final String notExistingId = "4395";
mvc.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + notExistingId).content("{}")
.contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isNotFound());
.contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isNotFound());
}
@Test
@@ -166,8 +168,7 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
createSingleTargetFilterQuery(idB, testQuery);
createSingleTargetFilterQuery(idC, testQuery);
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING)).andExpect(status().isOk())
.andDo(print())
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING)).andExpect(status().isOk()).andDo(print())
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(knownTargetAmount)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(knownTargetAmount)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(knownTargetAmount)))
@@ -252,9 +253,8 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
final String hrefPrefix = "http://localhost" + MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"
+ tfq.getId();
// test
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId()))
.andDo(print()).andExpect(status().isOk())
.andExpect(jsonPath(JSON_PATH_NAME, equalTo(knownName)))
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId())).andDo(print())
.andExpect(status().isOk()).andExpect(jsonPath(JSON_PATH_NAME, equalTo(knownName)))
.andExpect(jsonPath(JSON_PATH_QUERY, equalTo(knownQuery)))
.andExpect(jsonPath("$._links.self.href", equalTo(hrefPrefix)))
.andExpect(jsonPath("$._links.autoAssignDS.href", equalTo(hrefPrefix + "/autoAssignDS")));
@@ -402,8 +402,7 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
? "{\"id\":" + set.getId() + ", \"type\":\"" + actionType.getName() + "\"}"
: "{\"id\":" + set.getId() + "}";
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
.content(payload).contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isOk());
.content(payload).contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isOk());
final TargetFilterQuery updatedFilterQuery = targetFilterQueryManagement.get(tfq.getId()).get();
final MgmtActionType expectedActionType = actionType != null ? actionType : MgmtActionType.FORCED;
@@ -412,9 +411,8 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
assertThat(updatedFilterQuery.getAutoAssignActionType())
.isEqualTo(MgmtRestModelMapper.convertActionType(expectedActionType));
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId()))
.andDo(print()).andExpect(status().isOk())
.andExpect(jsonPath(JSON_PATH_NAME, equalTo(tfq.getName())))
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId())).andDo(print())
.andExpect(status().isOk()).andExpect(jsonPath(JSON_PATH_NAME, equalTo(tfq.getName())))
.andExpect(jsonPath(JSON_PATH_QUERY, equalTo(tfq.getQuery())))
.andExpect(jsonPath(JSON_PATH_AUTO_ASSIGN_DS, equalTo(set.getId().intValue())))
.andExpect(jsonPath(JSON_PATH_AUTO_ASSIGN_ACTION_TYPE, equalTo(expectedActionType.getName())))
@@ -427,8 +425,7 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
throws Exception {
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
.content("{\"id\":" + set.getId() + ", \"type\":\"" + MgmtActionType.TIMEFORCED.getName() + "\"}")
.contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isBadRequest())
.contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isBadRequest())
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS,
equalTo(InvalidAutoAssignActionTypeException.class.getName())))
.andExpect(jsonPath(JSON_PATH_ERROR_CODE,
@@ -491,7 +488,8 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
final DistributionSet set = testdataFactory.createDistributionSet(dsName);
final TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
targetFilterQueryManagement.updateAutoAssignDS(tfq.getId(), set.getId());
targetFilterQueryManagement
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(tfq.getId()).ds(set.getId()));
final TargetFilterQuery updatedFilterQuery = targetFilterQueryManagement.get(tfq.getId()).get();
@@ -514,6 +512,34 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
}
@Test
@Description("An auto assignment containing a weight is only accepted when weight is valide and multi assignment is on.")
public void weightValidation() throws Exception {
final Long filterId = createSingleTargetFilterQuery("filter1", "name==*").getId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final String invalideWeightRequest = new JSONObject().put("id", dsId).put("weight", Action.WEIGHT_MIN - 1)
.toString();
final String valideWeightRequest = new JSONObject().put("id", dsId).put("weight", 45).toString();
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
filterId).content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.multiassignmentNotEnabled")));
enableMultiAssignments();
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
filterId).content(invalideWeightRequest).contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.repo.constraintViolation")));
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
filterId).content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isOk());
final List<TargetFilterQuery> filters = targetFilterQueryManagement.findAll(PAGE).getContent();
assertThat(filters).hasSize(1);
assertThat(filters.get(0).getAutoAssignWeight().get()).isEqualTo(45);
}
private TargetFilterQuery createSingleTargetFilterQuery(final String name, final String query) {
return targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name(name).query(query));
}

View File

@@ -26,7 +26,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -40,6 +39,7 @@ import javax.validation.ConstraintViolationException;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.ActionFields;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
@@ -61,7 +61,6 @@ import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.eclipse.hawkbit.util.IpUtil;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Test;
import org.springframework.data.domain.PageRequest;
@@ -1876,7 +1875,8 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
final List<Long> dsIds = testdataFactory.createDistributionSets(2).stream().map(DistributionSet::getId)
.collect(Collectors.toList());
final JSONArray body = getAssignmentBody(dsIds);
final JSONArray body = new JSONArray();
dsIds.forEach(id -> body.put(getAssignmentObject(id, MgmtActionType.FORCED, 67)));
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(body.toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
@@ -1889,8 +1889,7 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final JSONArray body = getAssignmentBody(Collections.singletonList(dsId));
final JSONArray body = new JSONArray().put(getAssignmentObject(dsId, MgmtActionType.FORCED));
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(body.toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
@@ -1902,7 +1901,8 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final JSONArray body = getAssignmentBody(Arrays.asList(dsId, dsId));
final JSONObject assignment = getAssignmentObject(dsId, MgmtActionType.FORCED);
final JSONArray body = new JSONArray().put(assignment).put(assignment);
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(body.toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -1916,21 +1916,90 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
final List<Long> dsIds = testdataFactory.createDistributionSets(2).stream().map(DistributionSet::getId)
.collect(Collectors.toList());
final JSONArray body = getAssignmentBody(dsIds);
final JSONArray body = new JSONArray();
dsIds.forEach(id -> body.put(getAssignmentObject(id, MgmtActionType.FORCED, 76)));
enableMultiAssignments();
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(body.toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(2)));
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("total", equalTo(2)));
}
public static JSONArray getAssignmentBody(final Collection<Long> dsIds) throws JSONException {
final JSONArray body = new JSONArray();
for (final Long id : dsIds) {
final JSONObject obj = new JSONObject();
obj.put("id", id);
body.put(obj);
}
return body;
@Test
@Description("An assignment request containing a weight is only accepted when weight is valide and multi assignment is on.")
public void weightValidation() throws Exception {
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final int weight = 98;
final JSONObject bodyValid = getAssignmentObject(dsId, MgmtActionType.FORCED, weight);
final JSONObject bodyInvalid = getAssignmentObject(dsId, MgmtActionType.FORCED, Action.WEIGHT_MIN - 1);
enableMultiAssignments();
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(bodyInvalid.toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.repo.constraintViolation")));
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(bodyValid.toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).get().collect(Collectors.toList());
assertThat(actions).size().isEqualTo(1);
assertThat(actions.get(0).getWeight()).get().isEqualTo(weight);
}
@Test
@Description("An assignment request containing a valid weight when multi assignment is off.")
public void weightWithSingleAssignment() throws Exception {
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final JSONObject bodyValid = getAssignmentObject(dsId, MgmtActionType.FORCED, 98);
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(bodyValid.toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.multiassignmentNotEnabled")));
}
@Test
@Description("An assignment request containing a valid weight when multi assignment is on.")
public void weightWithMultiAssignment() throws Exception {
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final int weight = 98;
final JSONObject bodyValid = getAssignmentObject(dsId, MgmtActionType.FORCED, weight);
enableMultiAssignments();
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(bodyValid.toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).get().collect(Collectors.toList());
assertThat(actions).size().isEqualTo(1);
assertThat(actions.get(0).getWeight()).get().isEqualTo(weight);
}
@Test
@Description("Get weight of action")
public void getActionWeight() throws Exception {
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final int customWeightHigh = 800;
final int customWeightLow = 300;
assignDistributionSet(dsId, targetId);
enableMultiAssignments();
assignDistributionSet(dsId, targetId, customWeightHigh);
assignDistributionSet(dsId, targetId, customWeightLow);
mvc.perform(get("/rest/v1/targets/{targetId}/actions", targetId)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "WEIGHT:ASC")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("content.[0].weight").doesNotExist())
.andExpect(jsonPath("content.[1].weight", equalTo(customWeightLow)))
.andExpect(jsonPath("content.[2].weight", equalTo(customWeightHigh)));
}
}

View File

@@ -83,6 +83,7 @@ public class ResponseExceptionHandler {
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_AUTO_ASSIGN_DISTRIBUTION_SET_INVALID, HttpStatus.BAD_REQUEST);
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_CONFIGURATION_VALUE_CHANGE_NOT_ALLOWED, HttpStatus.FORBIDDEN);
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_MULTIASSIGNMENT_NOT_ENABLED, HttpStatus.BAD_REQUEST);
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_NO_WEIGHT_PROVIDED_IN_MULTIASSIGNMENT_MODE, HttpStatus.BAD_REQUEST);
}
private static HttpStatus getStatusOrDefault(final SpServerError error) {

View File

@@ -449,25 +449,27 @@ public abstract class JsonBuilder {
public static String rollout(final String name, final String description, final int groupSize,
final long distributionSetId, final String targetFilterQuery, final RolloutGroupConditions conditions) {
return rollout(name, description, groupSize, distributionSetId, targetFilterQuery, conditions, null, null);
return rollout(name, description, groupSize, distributionSetId, targetFilterQuery, conditions, null, null,
null);
}
public static String rollout(final String name, final String description, final Integer groupSize,
final long distributionSetId, final String targetFilterQuery, final RolloutGroupConditions conditions,
final List<RolloutGroup> groups) {
return rollout(name, description, groupSize, distributionSetId, targetFilterQuery, conditions, groups, null);
return rollout(name, description, groupSize, distributionSetId, targetFilterQuery, conditions, groups, null,
null);
}
public static String rollout(final String name, final String description, final Integer groupSize,
final long distributionSetId, final String targetFilterQuery, final RolloutGroupConditions conditions,
final String type) {
return rollout(name, description, groupSize, distributionSetId, targetFilterQuery, conditions, null, type);
return rollout(name, description, groupSize, distributionSetId, targetFilterQuery, conditions, null, type,
null);
}
public static String rollout(final String name, final String description, final Integer groupSize,
final long distributionSetId, final String targetFilterQuery, final RolloutGroupConditions conditions,
final List<RolloutGroup> groups, final String type) {
final List<RolloutGroup> groups, final String type, final Integer weight) {
final JSONObject json = new JSONObject();
try {
@@ -481,6 +483,10 @@ public abstract class JsonBuilder {
json.put("type", type);
}
if (weight != null) {
json.put("weight", weight);
}
if (conditions != null) {
final JSONObject successCondition = new JSONObject();

View File

@@ -25,11 +25,13 @@ import java.util.stream.Collectors;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.ddi.rest.resource.DdiApiConfiguration;
import org.eclipse.hawkbit.mgmt.rest.resource.MgmtApiConfiguration;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
import org.eclipse.hawkbit.repository.model.DeploymentRequestBuilder;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
@@ -37,6 +39,7 @@ import org.eclipse.hawkbit.repository.test.TestConfiguration;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
import org.eclipse.hawkbit.rest.RestConfiguration;
import org.eclipse.hawkbit.rest.util.FilterHttpResponse;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.beans.factory.annotation.Autowired;
@@ -98,8 +101,13 @@ public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrati
}
public static MyFieldFieldDesc requestFieldWithPath(final String path, final boolean mandatory) {
return requestFieldWithPath(path, mandatory, mandatory ? "X" : "");
}
private static MyFieldFieldDesc requestFieldWithPath(final String path, final boolean mandatory,
final String mandatoryMessage) {
final MyFieldFieldDesc myFieldDesc = new MyFieldFieldDesc(path);
myFieldDesc.attributes(key("mandatory").value(mandatory ? "X" : ""));
myFieldDesc.attributes(key("mandatory").value(mandatoryMessage));
// defaults
myFieldDesc.attributes(key("value").value(""));
@@ -118,6 +126,10 @@ public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrati
return requestFieldWithPath(path, false);
}
public static MyFieldFieldDesc requestFieldWithPathMandatoryInMultiAssignMode(final String path) {
return requestFieldWithPath(path, false, "when multi-assignment is enabled");
}
public static class MyFieldFieldDesc extends SubsectionDescriptor {
/**
@@ -154,11 +166,17 @@ public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrati
final Target savedTarget = targetManagement.create(entityFactory.target().create().controllerId(name)
.status(TargetUpdateStatus.UNKNOWN).address("http://192.168.0.1").description("My name is " + name)
.lastTargetQuery(System.currentTimeMillis()));
final List<Target> updatedTargets = maintenanceWindowSchedule == null
? assignWithoutMaintenanceWindow(distributionSet, savedTarget, timeforced)
: assignWithMaintenanceWindow(distributionSet, savedTarget, timeforced, maintenanceWindowSchedule,
maintenanceWindowDuration, maintenanceWindowTimeZone);
final DeploymentRequestBuilder deploymentRequestBuilder = DeploymentManagement
.deploymentRequest(savedTarget.getControllerId(), distributionSet.getId())
.setMaintenance(maintenanceWindowSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone);
if (timeforced) {
deploymentRequestBuilder.setActionType(ActionType.TIMEFORCED);
}
if (isMultiAssignmentsEnabled()) {
deploymentRequestBuilder.setWeight(600);
}
final List<Target> updatedTargets = makeAssignment(deploymentRequestBuilder.build()).getAssignedEntity()
.stream().map(Action::getTarget).collect(Collectors.toList());
if (inSync) {
feedbackToByInSync(distributionSet);
@@ -167,28 +185,6 @@ public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrati
return updatedTargets.get(0);
}
private List<Target> assignWithoutMaintenanceWindow(final DistributionSet distributionSet, final Target savedTarget,
final boolean timeforced) {
final List<Action> actions = timeforced
? assignDistributionSet(distributionSet.getId(), savedTarget.getControllerId(), ActionType.TIMEFORCED)
.getAssignedEntity()
: assignDistributionSet(distributionSet, savedTarget).getAssignedEntity();
return actions.stream().map(Action::getTarget).collect(Collectors.toList());
}
private List<Target> assignWithMaintenanceWindow(final DistributionSet distributionSet, final Target savedTarget,
final boolean timeforced, final String maintenanceWindowSchedule, final String maintenanceWindowDuration,
final String maintenanceWindowTimeZone) {
final List<Action> actions = timeforced
? assignDistributionSetWithMaintenanceWindow(distributionSet.getId(), savedTarget.getControllerId(),
ActionType.TIMEFORCED, maintenanceWindowSchedule, maintenanceWindowDuration,
maintenanceWindowTimeZone).getAssignedEntity()
: assignDistributionSetWithMaintenanceWindow(distributionSet.getId(), savedTarget.getControllerId(),
maintenanceWindowSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone)
.getAssignedEntity();
return actions.stream().map(Action::getTarget).collect(Collectors.toList());
}
protected DistributionSet createDistributionSet() {
DistributionSet distributionSet = testdataFactory.createDistributionSet("");
distributionSet = distributionSetManagement.update(entityFactory.distributionSet()
@@ -314,4 +310,9 @@ public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrati
parameterWithName("q").description(ApiModelPropertiesGeneric.FIQL));
}
protected boolean isMultiAssignmentsEnabled() {
return Boolean.TRUE.equals(tenantConfigurationManagement
.getConfigurationValue(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, Boolean.class).getValue());
}
}

View File

@@ -109,6 +109,8 @@ public final class MgmtApiModelProperties {
public static final String ROLLOUT_LINKS_GROUPS = "Link to retrieve the groups a rollout";
public static final String ROLLOUT_START_ASYNC = "Start the rollout asynchronous";
public static final String RESULTING_ACTIONS_WEIGHT = "Weight of the resulting Actions";
public static final String UPDATE_STATUS = "Current update status of the target.";
public static final String TARGET_ATTRIBUTES = "Target attributes.";
@@ -138,6 +140,8 @@ public final class MgmtApiModelProperties {
public static final String ACTION_LIST = "List of actions.";
public static final String ACTION_WEIGHT = "Weight of the action showing the importance of the update.";
public static final String IP_ADDRESS = "Last known IP address of the target. Only presented if IP address of the target itself is known (connected directly through DDI API).";
public static final String ADDRESS = "The last known address URI of the target. Includes information of the target is connected either directly (DDI) through HTTP or indirectly (DMF) through amqp.";
@@ -188,6 +192,7 @@ public final class MgmtApiModelProperties {
// request parameter
public static final String FORCETIME = "Forcetime in milliseconds.";
public static final String FORCE = "Force as boolean.";
public static final String ASSIGNMENT_WEIGHT = "Importance of the assignment.";
public static final String ASSIGNMENT_TYPE = "The type of the assignment.";
public static final String TARGET_ASSIGNED = "The number of targets that have been assigned as part of this operation.";
public static final String TARGET_ASSIGNED_ALREADY = "The number of targets which already had been the assignment.";

View File

@@ -385,6 +385,9 @@ public class DistributionSetsDocumentationTest extends AbstractApiRestDocumentat
.description(MgmtApiModelProperties.OFFLINE_UPDATE).optional()),
requestFields(
requestFieldWithPath("[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
requestFieldWithPathMandatoryInMultiAssignMode("[].weight")
.description(MgmtApiModelProperties.ASSIGNMENT_WEIGHT)
.type(JsonFieldType.NUMBER).attributes(key("value").value("0 - 1000")),
optionalRequestFieldWithPath("[].forcetime")
.description(MgmtApiModelProperties.FORCETIME),
optionalRequestFieldWithPath("[].maintenanceWindow")

View File

@@ -23,10 +23,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction;
@@ -52,6 +51,8 @@ import org.springframework.restdocs.payload.FieldDescriptor;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.restdocs.snippet.Snippet;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@@ -80,7 +81,7 @@ public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentati
@Description("Handles the GET request of retrieving all rollouts. Required Permission: "
+ SpPermission.READ_ROLLOUT)
public void getRollouts() throws Exception {
enableMultiAssignments();
createRolloutEntity();
mockMvc.perform(get(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING).accept(MediaTypes.HAL_JSON_VALUE))
@@ -113,6 +114,8 @@ public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentati
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "id").description(ApiModelPropertiesGeneric.ITEM_ID));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "name").description(ApiModelPropertiesGeneric.NAME));
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "weight")
.description(MgmtApiModelProperties.RESULTING_ACTIONS_WEIGHT).type(JsonFieldType.NUMBER).optional());
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "deleted").description(ApiModelPropertiesGeneric.DELETED));
allFieldDescriptor
.add(fieldWithPath(arrayPrefix + "description").description(ApiModelPropertiesGeneric.DESCRPTION));
@@ -159,7 +162,7 @@ public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentati
@Description("Handles the GET request of retrieving a single rollout. Required Permission: "
+ SpPermission.READ_ROLLOUT)
public void getRollout() throws Exception {
enableMultiAssignments();
final Rollout rollout = createRolloutEntity();
mockMvc.perform(get(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}", rollout.getId())
@@ -195,47 +198,47 @@ public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentati
.contentType(MediaTypes.HAL_JSON_UTF8).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaTypes.HAL_JSON_UTF8))
.andDo(this.document.document(
requestFields(requestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
optionalRequestFieldWithPath("type").description(
MgmtApiModelProperties.ROLLOUT_TYPE).attributes(
key("value").value("['soft', 'forced', 'timeforced', 'downloadonly']")),
requestFieldWithPath("distributionSetId")
.description(MgmtApiModelProperties.ROLLOUT_DS_ID),
requestFieldWithPath("targetFilterQuery")
.description(MgmtApiModelProperties.ROLLOUT_FILTER_QUERY),
requestFieldWithPath("amountGroups")
.description(MgmtApiModelProperties.ROLLOUT_AMOUNT_GROUPS),
optionalRequestFieldWithPath("description")
.description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("successCondition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION),
optionalRequestFieldWithPath("successCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("successCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_EXP),
optionalRequestFieldWithPath("successAction")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION),
optionalRequestFieldWithPath("successAction.action")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_ACTION)
.attributes(key("value").value("['nextgroup']")),
optionalRequestFieldWithPath("successAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_EXP),
optionalRequestFieldWithPath("errorCondition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION),
optionalRequestFieldWithPath("errorCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("errorCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_EXP),
optionalRequestFieldWithPath("errorAction")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION),
optionalRequestFieldWithPath("errorAction.action")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_ACTION)
.attributes(key("value").value("['pause']")),
optionalRequestFieldWithPath("errorAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_EXP)),
.andDo(this.document.document(requestFields(
requestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPathMandatoryInMultiAssignMode("weight").type(JsonFieldType.NUMBER)
.description(MgmtApiModelProperties.RESULTING_ACTIONS_WEIGHT)
.attributes(key("value").value("0 - 1000")),
requestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
optionalRequestFieldWithPath("type").description(MgmtApiModelProperties.ROLLOUT_TYPE)
.attributes(key("value").value("['soft', 'forced', 'timeforced', 'downloadonly']")),
requestFieldWithPath("distributionSetId").description(MgmtApiModelProperties.ROLLOUT_DS_ID),
requestFieldWithPath("targetFilterQuery")
.description(MgmtApiModelProperties.ROLLOUT_FILTER_QUERY),
requestFieldWithPath("amountGroups").description(MgmtApiModelProperties.ROLLOUT_AMOUNT_GROUPS),
optionalRequestFieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("successCondition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION),
optionalRequestFieldWithPath("successCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("successCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_EXP),
optionalRequestFieldWithPath("successAction")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION),
optionalRequestFieldWithPath("successAction.action")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_ACTION)
.attributes(key("value").value("['nextgroup']")),
optionalRequestFieldWithPath("successAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_EXP),
optionalRequestFieldWithPath("errorCondition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION),
optionalRequestFieldWithPath("errorCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("errorCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_EXP),
optionalRequestFieldWithPath("errorAction")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION),
optionalRequestFieldWithPath("errorAction.action")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_ACTION)
.attributes(key("value").value("['pause']")),
optionalRequestFieldWithPath("errorAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_EXP)),
getRolloutResponseFields(false, true)));
@@ -283,77 +286,83 @@ public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentati
.contentType(MediaType.APPLICATION_JSON).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaTypes.HAL_JSON_UTF8))
.andDo(this.document.document(requestFields(
requestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPath("distributionSetId").description(MgmtApiModelProperties.ROLLOUT_DS_ID),
requestFieldWithPath("targetFilterQuery")
.description(MgmtApiModelProperties.ROLLOUT_FILTER_QUERY),
optionalRequestFieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("successCondition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION),
optionalRequestFieldWithPath("successCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("successCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_EXP),
optionalRequestFieldWithPath("successAction")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION),
optionalRequestFieldWithPath("successAction.action")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_ACTION)
.attributes(key("value").value("['nextgroup']")),
optionalRequestFieldWithPath("successAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_EXP),
optionalRequestFieldWithPath("errorCondition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION),
optionalRequestFieldWithPath("errorCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("errorCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_EXP),
optionalRequestFieldWithPath("errorAction")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION),
optionalRequestFieldWithPath("errorAction.action")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_ACTION)
.attributes(key("value").value("['pause']")),
optionalRequestFieldWithPath("errorAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_EXP),
requestFieldWithPath("groups").description(MgmtApiModelProperties.ROLLOUT_GROUPS),
requestFieldWithPath("groups[].name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPath("groups[].description").description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("groups[].targetFilterQuery")
.description(MgmtApiModelProperties.ROLLOUT_GROUP_FILTER_QUERY),
optionalRequestFieldWithPath("groups[].targetPercentage")
.description(MgmtApiModelProperties.ROLLOUT_GROUP_TARGET_PERCENTAGE)
.attributes(key("value").value("0..100")),
optionalRequestFieldWithPath("groups[].successCondition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION),
optionalRequestFieldWithPath("groups[].successCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("groups[].successCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_EXP),
optionalRequestFieldWithPath("groups[].successAction")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION),
optionalRequestFieldWithPath("groups[].successAction.action")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_ACTION)
.attributes(key("value").value("['nextgroup']")),
optionalRequestFieldWithPath("groups[].successAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_EXP),
optionalRequestFieldWithPath("groups[].errorCondition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION),
optionalRequestFieldWithPath("groups[].errorCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("groups[].errorCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_EXP),
optionalRequestFieldWithPath("groups[].errorAction")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION),
optionalRequestFieldWithPath("groups[].errorAction.action")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_ACTION)
.attributes(key("value").value("['pause']")),
optionalRequestFieldWithPath("groups[].errorAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_EXP)),
.andDo(this.document.document(
requestFields(requestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPathMandatoryInMultiAssignMode("weight")
.type(JsonFieldType.NUMBER)
.description(MgmtApiModelProperties.RESULTING_ACTIONS_WEIGHT)
.attributes(key("value").value("0 - 1000")),
requestFieldWithPath("distributionSetId")
.description(MgmtApiModelProperties.ROLLOUT_DS_ID),
requestFieldWithPath("targetFilterQuery")
.description(MgmtApiModelProperties.ROLLOUT_FILTER_QUERY),
optionalRequestFieldWithPath("description")
.description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("successCondition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION),
optionalRequestFieldWithPath("successCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("successCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_EXP),
optionalRequestFieldWithPath("successAction")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION),
optionalRequestFieldWithPath("successAction.action")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_ACTION)
.attributes(key("value").value("['nextgroup']")),
optionalRequestFieldWithPath("successAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_EXP),
optionalRequestFieldWithPath("errorCondition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION),
optionalRequestFieldWithPath("errorCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("errorCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_EXP),
optionalRequestFieldWithPath("errorAction")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION),
optionalRequestFieldWithPath("errorAction.action")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_ACTION)
.attributes(key("value").value("['pause']")),
optionalRequestFieldWithPath("errorAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_EXP),
requestFieldWithPath("groups").description(MgmtApiModelProperties.ROLLOUT_GROUPS),
requestFieldWithPath("groups[].name").description(ApiModelPropertiesGeneric.NAME),
requestFieldWithPath("groups[].description")
.description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("groups[].targetFilterQuery")
.description(MgmtApiModelProperties.ROLLOUT_GROUP_FILTER_QUERY),
optionalRequestFieldWithPath("groups[].targetPercentage")
.description(MgmtApiModelProperties.ROLLOUT_GROUP_TARGET_PERCENTAGE)
.attributes(key("value").value("0..100")),
optionalRequestFieldWithPath("groups[].successCondition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION),
optionalRequestFieldWithPath("groups[].successCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("groups[].successCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_CONDITION_EXP),
optionalRequestFieldWithPath("groups[].successAction")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION),
optionalRequestFieldWithPath("groups[].successAction.action")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_ACTION)
.attributes(key("value").value("['nextgroup']")),
optionalRequestFieldWithPath("groups[].successAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_SUCCESS_ACTION_EXP),
optionalRequestFieldWithPath("groups[].errorCondition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION),
optionalRequestFieldWithPath("groups[].errorCondition.condition")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_CONDITION)
.attributes(key("value").value("['threshold']")),
optionalRequestFieldWithPath("groups[].errorCondition.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_CONDITION_EXP),
optionalRequestFieldWithPath("groups[].errorAction")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION),
optionalRequestFieldWithPath("groups[].errorAction.action")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_ACTION)
.attributes(key("value").value("['pause']")),
optionalRequestFieldWithPath("groups[].errorAction.expression")
.description(MgmtApiModelProperties.ROLLOUT_ERROR_ACTION_EXP)),
getRolloutResponseFields(false, true)));
}
@@ -626,11 +635,13 @@ public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentati
private Rollout createRolloutEntity() {
testdataFactory.createTargets(20, "exampleTarget");
final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name("exampleRollout")
.targetFilterQuery("controllerId==exampleTarget*").set(testdataFactory.createDistributionSet()),
10, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "10").build());
final RolloutCreate rolloutCreate = entityFactory.rollout().create().name("exampleRollout")
.targetFilterQuery("controllerId==exampleTarget*").set(testdataFactory.createDistributionSet());
if (isMultiAssignmentsEnabled()) {
rolloutCreate.weight(400);
}
final Rollout rollout = rolloutManagement.create(rolloutCreate, 10, new RolloutGroupConditionBuilder()
.withDefaults().successCondition(RolloutGroupSuccessCondition.THRESHOLD, "10").build());
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();

View File

@@ -31,6 +31,7 @@ import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
@@ -183,15 +184,16 @@ public class TargetFilterQueriesResourceDocumentationTest extends AbstractApiRes
@Test
@Description("Handles the POST request of setting a distribution set for auto assignment within SP. Required Permission: CREATE_TARGET.")
public void postAutoAssignDS() throws Exception {
enableMultiAssignments();
final TargetFilterQuery tfq = createTargetFilterQuery();
final DistributionSet distributionSet = createDistributionSet();
final String filterByDistSet = "{\"id\":\"" + distributionSet.getId() + "\", \"type\":\""
+ MgmtActionType.SOFT.getName() + "\"}";
final String autoAssignBody = new JSONObject().put("id", distributionSet.getId())
.put("type", MgmtActionType.SOFT.getName()).put("weight", 200).toString();
this.mockMvc
.perform(
post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
tfq.getId()).contentType(MediaType.APPLICATION_JSON).content(filterByDistSet))
tfq.getId()).contentType(MediaType.APPLICATION_JSON).content(autoAssignBody.toString()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("targetFilterQueryId")
@@ -199,7 +201,10 @@ public class TargetFilterQueriesResourceDocumentationTest extends AbstractApiRes
requestFields(requestFieldWithPath("id").description(MgmtApiModelProperties.DS_ID),
optionalRequestFieldWithPath("type")
.description(MgmtApiModelProperties.ACTION_FORCE_TYPE)
.attributes(key("value").value("['forced', 'soft', 'downloadonly']"))),
.attributes(key("value").value("['forced', 'soft', 'downloadonly']")),
requestFieldWithPathMandatoryInMultiAssignMode("weight")
.description(MgmtApiModelProperties.RESULTING_ACTIONS_WEIGHT)
.attributes(key("value").value("0 - 1000"))),
getResponseFieldTargetFilterQuery(false)));
}
@@ -227,6 +232,9 @@ public class TargetFilterQueriesResourceDocumentationTest extends AbstractApiRes
fieldWithPath(arrayPrefix + "autoAssignActionType")
.description(MgmtApiModelProperties.ACTION_FORCE_TYPE).type(JsonFieldType.STRING.toString())
.attributes(key("value").value("['forced', 'soft', 'downloadonly']")),
fieldWithPath(arrayPrefix + "autoAssignWeight")
.description(MgmtApiModelProperties.RESULTING_ACTIONS_WEIGHT)
.type(JsonFieldType.NUMBER.toString()),
fieldWithPath(arrayPrefix + "createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath(arrayPrefix + "createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath(arrayPrefix + "lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT),
@@ -235,7 +243,8 @@ public class TargetFilterQueriesResourceDocumentationTest extends AbstractApiRes
.description(MgmtApiModelProperties.TARGET_FILTER_QUERY_LINK_AUTO_ASSIGN_DS));
}
private String createTargetFilterQueryJson(final String name, final String query) throws JsonProcessingException {
private String createTargetFilterQueryJson(final String name, final String query)
throws JsonProcessingException {
final Map<String, Object> target = new HashMap<>();
target.put("name", name);
target.put("query", query);
@@ -249,6 +258,7 @@ public class TargetFilterQueriesResourceDocumentationTest extends AbstractApiRes
private TargetFilterQuery createTargetFilterQueryWithDS(final DistributionSet distributionSet) {
final TargetFilterQuery targetFilterQuery = createTargetFilterQuery();
return targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), distributionSet.getId());
return targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId()));
}
}

View File

@@ -203,6 +203,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Handles the GET request of retrieving the full action history of a specific target. Required Permission: READ_TARGET.")
public void getActionsFromTarget() throws Exception {
enableMultiAssignments();
generateActionForTarget(targetId);
mockMvc.perform(
@@ -229,12 +230,14 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
.description(MgmtApiModelProperties.ACTION_EXECUTION_STATUS)
.attributes(key("value").value("['finished', 'pending']")),
fieldWithPath("content[]._links").description(MgmtApiModelProperties.LINK_TO_ACTION),
fieldWithPath("content[].id").description(MgmtApiModelProperties.ACTION_ID))));
fieldWithPath("content[].id").description(MgmtApiModelProperties.ACTION_ID),
fieldWithPath("content[].weight").description(MgmtApiModelProperties.ACTION_WEIGHT))));
}
@Test
@Description("Handles the GET request of retrieving the full action history of a specific target with maintenance window. Required Permission: READ_TARGET.")
public void getActionsFromTargetWithMaintenanceWindow() throws Exception {
enableMultiAssignments();
generateActionForTarget(targetId, true, false, getTestSchedule(2), getTestDuration(1), getTestTimeZone());
mockMvc.perform(
@@ -262,6 +265,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
.attributes(key("value").value("['finished', 'pending']")),
fieldWithPath("content[]._links").description(MgmtApiModelProperties.LINK_TO_ACTION),
fieldWithPath("content[].id").description(MgmtApiModelProperties.ACTION_ID),
fieldWithPath("content[].weight").description(MgmtApiModelProperties.ACTION_WEIGHT),
fieldWithPath("content[].maintenanceWindow")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW),
fieldWithPath("content[].maintenanceWindow.schedule")
@@ -317,6 +321,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Handles the GET request of retrieving a specific action on a specific target. Required Permission: READ_TARGET.")
public void getActionFromTarget() throws Exception {
enableMultiAssignments();
final Action action = generateActionForTarget(targetId, true, true);
assertThat(deploymentManagement.findAction(action.getId()).get().getActionType())
.isEqualTo(ActionType.TIMEFORCED);
@@ -330,6 +335,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
responseFields(fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("id").description(MgmtApiModelProperties.ACTION_ID),
fieldWithPath("weight").description(MgmtApiModelProperties.ACTION_WEIGHT),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
.type("String"),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
@@ -351,6 +357,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Handles the GET request of retrieving a specific action on a specific target. Required Permission: READ_TARGET.")
public void getActionFromTargetWithMaintenanceWindow() throws Exception {
enableMultiAssignments();
final Action action = generateActionForTarget(targetId, true, true, getTestSchedule(2), getTestDuration(1),
getTestTimeZone());
@@ -363,6 +370,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
responseFields(fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
fieldWithPath("id").description(MgmtApiModelProperties.ACTION_ID),
fieldWithPath("weight").description(MgmtApiModelProperties.ACTION_WEIGHT),
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
.type("String"),
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
@@ -514,6 +522,9 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
.description(MgmtApiModelProperties.OFFLINE_UPDATE).optional()),
requestFields(
requestFieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
requestFieldWithPathMandatoryInMultiAssignMode("weight")
.description(MgmtApiModelProperties.ASSIGNMENT_WEIGHT)
.type(JsonFieldType.NUMBER).attributes(key("value").value("0 - 1000")),
optionalRequestFieldWithPath("forcetime").description(MgmtApiModelProperties.FORCETIME),
optionalRequestFieldWithPath("maintenanceWindow")
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW),
@@ -537,12 +548,12 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
final long forceTime = System.currentTimeMillis();
final JSONArray body = new JSONArray();
body.put(new JSONObject().put("id", sets.get(1).getId()).put("type", "timeforced")
body.put(new JSONObject().put("id", sets.get(1).getId()).put("weight", 500).put("type", "timeforced")
.put("forcetime", forceTime)
.put("maintenanceWindow", new JSONObject().put("schedule", getTestSchedule(100))
.put("duration", getTestDuration(10)).put("timezone", getTestTimeZone())))
.toString();
body.put(new JSONObject().put("id", sets.get(0).getId()).put("type", "forced"));
body.put(new JSONObject().put("id", sets.get(0).getId()).put("type", "forced").put("weight", 800));
enableMultiAssignments();
mockMvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/"
@@ -555,6 +566,9 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
.description(MgmtApiModelProperties.OFFLINE_UPDATE).optional()),
requestFields(
requestFieldWithPath("[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
requestFieldWithPathMandatoryInMultiAssignMode("[].weight")
.description(MgmtApiModelProperties.ASSIGNMENT_WEIGHT)
.attributes(key("value").value("0 - 1000")),
optionalRequestFieldWithPath("[].forcetime")
.description(MgmtApiModelProperties.FORCETIME),
optionalRequestFieldWithPath("[].maintenanceWindow")