Feature/java11 build (#1280)

* hawkBit on Java 11

Signed-off-by: Dominic Schabel <dominic.schabel@bosch.io>

* Preparing java 11 build

- Update eclipse-link maven plugin dependencies
- Fixing warnings, adopt to java-11 style

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>

* Preparing java 11 build

- Fixing warnings, adapt to java-11 style
- Added since to deprecated

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>

* Fixing sonar warnings

- removed deprecated API

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>

* Fixing sonar warnings & failing test

- Added suppressWarning
- added WithSpringAuthorityRule to clean-up listener

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>

* Compile warnings

- Test if final causes issues in tests

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>

* Removed deprecated code

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>

* Reverted changes

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>

* Removed final as this causes invalid reflective access exceptions

- The eclipselink generated classes seem to modify the field directly
- update plugin version

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>

* Upgrade eclipselink from 2.7.9 to 2.7.10

* Remove @deprecated endpoints from MgmtTargetTagResource

* Remove dependencies already defined in eclipselink-maven-plugin

* Try eclipselink 2.7.11-RC1

* Set project encoding to UTF-8

* Upgrade surefire and failsafe plugins to 3.0.0-M7

* Try fixed string instead of a random generated one

* Replace JsonBuilder by Jackson ObjectMapper usage

* Use JsonBuilder again

* Use APPLICATION_JSON_UTF8 instead of APPLICATION_JSON

* Try to replace com.vaadin.external.google:android-json by org.json:json

* Add debugging outputs

* Improve debugging outputs

* Improve debugging outputs

* Use Jackson instead of JsonBuilder

* Use Jackson instead of JsonBuilder 2nd part

* Use Spring json dependency

* Use eclipselink 2.7.11

* Fix RootControllerDocumentationTest

* Improve helper methods of AbstractDDiApiIntegrationTest

* Upgrade SpringBoot and SpringCloud versions

* Improve deprecation notice for 0.3.0M8

* Fix BaseAmqpServiceTest

* Fix SpecificationsBuilderTest

* Removed deprecated code

* Define maven-enforcer-plugin version

* Remove com.google.code.findbugs.jsr305

Signed-off-by: Florian Ruschbaschan <florian.ruschbaschan@bosch.io>

* Update circleci image to openjdk:openjdk:11.0.13-jdk-buster

Signed-off-by: Florian Ruschbaschan <florian.ruschbaschan@bosch.io>

* Fix javadoc generation and license check

Signed-off-by: Florian Ruschbaschan <florian.ruschbaschan@bosch.io>

* Fix review findings

Signed-off-by: Florian Ruschbaschan <florian.ruschbaschan@bosch.io>

Signed-off-by: Dominic Schabel <dominic.schabel@bosch.io>
Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>
Signed-off-by: Florian Ruschbaschan <florian.ruschbaschan@bosch.io>
Co-authored-by: Dominic Schabel <dominic.schabel@bosch.io>
Co-authored-by: Peter Vigier <Peter.Vigier@bosch.io>
Co-authored-by: Markus Block <markus.block@bosch-si.com>
This commit is contained in:
Florian Ruschbaschan
2022-09-19 10:33:31 +02:00
committed by GitHub
parent 537548defb
commit 32718676a4
36 changed files with 562 additions and 825 deletions

View File

@@ -29,21 +29,15 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* </p>
*
* <p>
* The answer header would look like: { "id": "51659181", "time":
* "20140511T121314", "status": { "execution": "closed", "result": { "final":
* "success", "progress": {} } "details": [], } }
* The answer header would look like: { "time": "20140511T121314", "status": {
* "execution": "closed", "result": { "final": "success", "progress": {} }
* "details": [], } }
* </p>
*
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class DdiActionFeedback {
/**
* @deprecated
* This ID is always given by the actionId path variable.
* Will be removed in future versions.
*/
@Deprecated
private final Long id;
private final String time;
@NotNull
@@ -51,27 +45,20 @@ public class DdiActionFeedback {
private final DdiStatus status;
/**
* Constructor.
*
* @param id
* of the actions the feedback is for
* Constructs an action-feedback
*
* @param time
* of the feedback
* time of feedback
* @param status
* is the feedback itself
* status to be appended to the action
*/
@JsonCreator
public DdiActionFeedback(@JsonProperty("id") final Long id, @JsonProperty("time") final String time,
@JsonProperty("status") final DdiStatus status) {
this.id = id;
public DdiActionFeedback(@JsonProperty(value = "time", required = true) final String time,
@JsonProperty(value = "status", required = true) final DdiStatus status) {
this.time = time;
this.status = status;
}
public Long getId() {
return id;
}
public String getTime() {
return time;
}
@@ -82,7 +69,7 @@ public class DdiActionFeedback {
@Override
public String toString() {
return "ActionFeedback [id=" + id + ", time=" + time + ", status=" + status + "]";
return "ActionFeedback [time=" + time + ", status=" + status + "]";
}
}

View File

@@ -61,16 +61,6 @@ public final class DdiRestConstants {
*/
public static final String MEDIA_TYPE_CBOR = "application/cbor";
/**
* Media type for CBOR content with strings encoded as UTF-8. Technically
* redundant since CBOR always uses UTF-8, but Spring will append it
* regardless.
* @deprecated Since the Spring Framework (v5.2.4.RELEASE) dropped the charset attribute
* from content type headers, please use {@link DdiRestConstants#MEDIA_TYPE_CBOR} instead.
*/
@Deprecated
public static final String MEDIA_TYPE_CBOR_UTF8 = "application/cbor;charset=UTF-8";
private DdiRestConstants() {
// constant class, private constructor.
}

View File

@@ -13,8 +13,10 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import java.io.IOException;
import java.time.Instant;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
@@ -22,57 +24,41 @@ import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.junit.jupiter.api.Test;
/**
* Test serializability of DDI api model 'DdiActionFeedback'
* Test serialization of DDI api model 'DdiActionFeedback'
*/
@Feature("Unit Tests - Direct Device Integration API")
@Story("Serializability of DDI api Models")
@Story("Serialization of DDI api Models")
public class DdiActionFeedbackTest {
private ObjectMapper mapper = new ObjectMapper();
private final ObjectMapper mapper = new ObjectMapper();
@Test
@Description("Verify the correct serialization and deserialization of the model")
public void shouldSerializeAndDeserializeObject() throws IOException {
// Setup
Long id = 123L;
String time = "20190809T121314";
DdiStatus ddiStatus = new DdiStatus(DdiStatus.ExecutionStatus.CLOSED, null, Lists.emptyList());
DdiActionFeedback ddiActionFeedback = new DdiActionFeedback(id, time, ddiStatus);
final String time = Instant.now().toString();
final DdiStatus ddiStatus = new DdiStatus(DdiStatus.ExecutionStatus.CLOSED, null, Lists.emptyList());
final DdiActionFeedback ddiActionFeedback = new DdiActionFeedback(time, ddiStatus);
// Test
String serializedDdiActionFeedback = mapper.writeValueAsString(ddiActionFeedback);
DdiActionFeedback deserializedDdiActionFeedback = mapper.readValue(serializedDdiActionFeedback,
final String serializedDdiActionFeedback = mapper.writeValueAsString(ddiActionFeedback);
final DdiActionFeedback deserializedDdiActionFeedback = mapper.readValue(serializedDdiActionFeedback,
DdiActionFeedback.class);
assertThat(serializedDdiActionFeedback).contains(id.toString(), time);
assertThat(deserializedDdiActionFeedback.getId()).isEqualTo(id);
assertThat(serializedDdiActionFeedback).contains(time);
assertThat(deserializedDdiActionFeedback.getTime()).isEqualTo(time);
assertThat(deserializedDdiActionFeedback.getStatus().toString()).isEqualTo(ddiStatus.toString());
}
@Test
@Description("Verify the correct deserialization of a model with a additional unknown property")
public void shouldDeserializeObjectWithUnknownProperty() throws IOException {
// Setup
String serializedDdiActionFeedback = "{\"id\":1, \"time\":\"20190809T121314\", \"status\":{\"execution\":\"closed\", \"result\":null, \"details\":[]}, \"unknownProperty\": \"test\"}";
// Test
DdiActionFeedback ddiActionFeedback = mapper.readValue(serializedDdiActionFeedback, DdiActionFeedback.class);
assertThat(ddiActionFeedback.getId()).isEqualTo(1L);
assertThat(ddiActionFeedback.getTime()).matches("20190809T121314");
assertThat(deserializedDdiActionFeedback.getStatus()).hasToString(ddiStatus.toString());
}
@Test
@Description("Verify that deserialization fails for known properties with a wrong datatype")
public void shouldFailForObjectWithWrongDataTypes() throws IOException {
// Setup
String serializedDdiActionFeedback = "{\"id\": [1],\"time\":\"20190809T121314\",\"status\":{\"execution\":\"closed\",\"result\":null,\"details\":[]}}";
final String serializedDdiActionFeedback = "{\"time\":\"20190809T121314\",\"status\":{\"execution\": [closed],\"result\":null,\"details\":[]}}";
assertThatExceptionOfType(MismatchedInputException.class).isThrownBy(
() -> mapper.readValue(serializedDdiActionFeedback, DdiActionFeedback.class));
}
}
}

View File

@@ -27,7 +27,7 @@ import io.qameta.allure.Story;
* Check DDI api model classes for '@JsonIgnoreProperties' annotation
*/
@Feature("Unit Tests - Direct Device Integration API")
@Story("Serializability of DDI api Models")
@Story("Serialization of DDI api Models")
public class JsonIgnorePropertiesAnnotationTest {
@Test
@@ -35,15 +35,15 @@ public class JsonIgnorePropertiesAnnotationTest {
"This test verifies that all model classes within the 'org.eclipse.hawkbit.ddi.json.model' package are annotated with '@JsonIgnoreProperties(ignoreUnknown = true)'")
public void shouldCheckAnnotationsForAllModelClasses() throws IOException {
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
String packageName = this.getClass().getPackage().getName();
final String packageName = this.getClass().getPackage().getName();
ImmutableSet<ClassPath.ClassInfo> topLevelClasses = ClassPath.from(loader).getTopLevelClasses(packageName);
for (ClassPath.ClassInfo classInfo : topLevelClasses) {
Class<?> modelClass = classInfo.load();
final ImmutableSet<ClassPath.ClassInfo> topLevelClasses = ClassPath.from(loader).getTopLevelClasses(packageName);
for (final ClassPath.ClassInfo classInfo : topLevelClasses) {
final Class<?> modelClass = classInfo.load();
if (modelClass.getSimpleName().contains("Test") || modelClass.isEnum()) {
continue;
}
JsonIgnoreProperties annotation = modelClass.getAnnotation(JsonIgnoreProperties.class);
final JsonIgnoreProperties annotation = modelClass.getAnnotation(JsonIgnoreProperties.class);
assertThat(annotation).isNotNull();
assertThat(annotation.ignoreUnknown()).isTrue();
}

View File

@@ -212,7 +212,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
.orElseThrow(() -> new SoftwareModuleNotAssignedToTargetException(module, target.getControllerId()));
final String range = request.getHeader("Range");
String message;
final String message;
if (range != null) {
message = RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads range " + range + " of: "
+ request.getRequestURI();
@@ -327,7 +327,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
if (!action.isActive()) {
LOG.warn("Updating action {} with feedback {} not possible since action not active anymore.",
action.getId(), feedback.getId());
action.getId(), feedback.getStatus());
return new ResponseEntity<>(HttpStatus.GONE);
}
@@ -346,7 +346,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
messages.addAll(feedback.getStatus().getDetails());
}
Status status;
final Status status;
switch (feedback.getStatus().getExecution()) {
case CANCELED:
LOG.debug("Controller confirmed cancel (actionId: {}, controllerId: {}) as we got {} report.", actionId,
@@ -391,7 +391,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
private Status handleDefaultCase(final DdiActionFeedback feedback, final String controllerId, final Long actionId,
final List<String> messages) {
Status status;
final Status status;
LOG.debug("Controller reported intermediate status (actionId: {}, controllerId: {}) as we got {} report.",
actionId, controllerId, feedback.getStatus().getExecution());
status = Status.RUNNING;
@@ -401,7 +401,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
private Status handleClosedCase(final DdiActionFeedback feedback, final String controllerId, final Long actionId,
final List<String> messages) {
Status status;
final Status status;
LOG.debug("Controller reported closed (actionId: {}, controllerId: {}) as we got {} report.", actionId,
controllerId, feedback.getStatus().getExecution());
if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) {
@@ -482,8 +482,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
private DdiDeploymentBase generateDdiDeploymentBase(Target target, Action action,
Integer actionHistoryMessageCount) {
private DdiDeploymentBase generateDdiDeploymentBase(final Target target, final Action action,
final Integer actionHistoryMessageCount) {
final List<DdiChunk> chunks = DataConversionHelper.createChunks(target, action, artifactUrlHandler,
systemManagement, new ServletServerHttpRequest(requestResponseContextHolder.getHttpServletRequest()),
controllerManagement);
@@ -508,7 +508,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
final Long actionId, final EntityFactory entityFactory) {
final List<String> messages = new ArrayList<>();
Status status;
final Status status;
switch (feedback.getStatus().getExecution()) {
case CANCELED:
status = handleCaseCancelCanceled(feedback, target, actionId, messages);
@@ -536,7 +536,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
}
private static Status handleCancelClosedCase(final DdiActionFeedback feedback, final List<String> messages) {
Status status;
final Status status;
if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) {
status = Status.ERROR;
addMessageIfEmpty("Target was not able to complete cancellation", messages);
@@ -549,7 +549,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
private static Status handleCaseCancelCanceled(final DdiActionFeedback feedback, final Target target,
final Long actionId, final List<String> messages) {
Status status;
final Status status;
LOG.error(
"Target reported cancel for a cancel which is not supported by the server (actionId: {}, controllerId: {}) as we got {} report.",
actionId, target.getControllerId(), feedback.getStatus().getExecution());
@@ -570,7 +570,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
return verifyActionBelongsToTarget(action, target);
}
private Action verifyActionBelongsToTarget(Action action, Target target) {
private Action verifyActionBelongsToTarget(final Action action, final Target target) {
if (!action.getTarget().getId().equals(target.getId())) {
LOG.debug(GIVEN_ACTION_IS_NOT_ASSIGNED_TO_GIVEN_TARGET, action.getId(), target.getId());
throw new EntityNotFoundException(

View File

@@ -18,7 +18,15 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.time.Instant;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback;
import org.eclipse.hawkbit.ddi.json.model.DdiProgress;
import org.eclipse.hawkbit.ddi.json.model.DdiResult;
import org.eclipse.hawkbit.ddi.json.model.DdiStatus;
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Artifact;
@@ -38,6 +46,8 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
import com.fasterxml.jackson.dataformat.cbor.CBORGenerator;
import com.fasterxml.jackson.dataformat.cbor.CBORParser;
@@ -59,22 +69,23 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
protected static final String CANCEL_FEEDBACK = CANCEL_ACTION + "/feedback";
protected static final int ARTIFACT_SIZE = 5 * 1024;
private static final ObjectMapper objectMapper = new ObjectMapper();
/**
* Convert JSON to a CBOR equivalent.
*
*
* @param json
* JSON object to convert
* @return Equivalent CBOR data
* @throws IOException
* Invalid JSON input
*/
protected static byte[] jsonToCbor(String json) throws IOException {
JsonFactory jsonFactory = new JsonFactory();
JsonParser jsonParser = jsonFactory.createParser(json);
ByteArrayOutputStream out = new ByteArrayOutputStream();
CBORFactory cborFactory = new CBORFactory();
CBORGenerator cborGenerator = cborFactory.createGenerator(out);
protected static byte[] jsonToCbor(final String json) throws IOException {
final JsonFactory jsonFactory = new JsonFactory();
final JsonParser jsonParser = jsonFactory.createParser(json);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final CBORFactory cborFactory = new CBORFactory();
final CBORGenerator cborGenerator = cborFactory.createGenerator(out);
while (jsonParser.nextToken() != null) {
cborGenerator.copyCurrentEvent(jsonParser);
}
@@ -84,19 +95,19 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
/**
* Convert CBOR to JSON equivalent.
*
*
* @param input
* CBOR data to convert
* @return Equivalent JSON string
* @throws IOException
* Invalid CBOR input
*/
protected static String cborToJson(byte[] input) throws IOException {
CBORFactory cborFactory = new CBORFactory();
CBORParser cborParser = cborFactory.createParser(input);
JsonFactory jsonFactory = new JsonFactory();
StringWriter stringWriter = new StringWriter();
JsonGenerator jsonGenerator = jsonFactory.createGenerator(stringWriter);
protected static String cborToJson(final byte[] input) throws IOException {
final CBORFactory cborFactory = new CBORFactory();
final CBORParser cborParser = cborFactory.createParser(input);
final JsonFactory jsonFactory = new JsonFactory();
final StringWriter stringWriter = new StringWriter();
final JsonGenerator jsonGenerator = jsonFactory.createGenerator(stringWriter);
while (cborParser.nextToken() != null) {
jsonGenerator.copyCurrentEvent(cborParser);
}
@@ -106,7 +117,7 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
protected ResultActions postDeploymentFeedback(final String controllerId, final Long actionId, final String content,
final ResultMatcher statusMatcher) throws Exception {
return postDeploymentFeedback(MediaType.APPLICATION_JSON, controllerId, actionId, content.getBytes(),
return postDeploymentFeedback(MediaType.APPLICATION_JSON_UTF8, controllerId, actionId, content.getBytes(),
statusMatcher);
}
@@ -120,7 +131,7 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
protected ResultActions postCancelFeedback(final String controllerId, final Long actionId, final String content,
final ResultMatcher statusMatcher) throws Exception {
return postCancelFeedback(MediaType.APPLICATION_JSON, controllerId, actionId, content.getBytes(),
return postCancelFeedback(MediaType.APPLICATION_JSON_UTF8, controllerId, actionId, content.getBytes(),
statusMatcher);
}
@@ -164,7 +175,7 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
getDownloadAndUploadType(actionType), getDownloadAndUploadType(actionType));
}
private ResultActions verifyBasePayload(ResultActions resultActions, final String controllerId,
private ResultActions verifyBasePayload(final ResultActions resultActions, final String controllerId,
final DistributionSet ds, final Artifact artifact, final Artifact artifactSignature, final Long actionId,
final Long osModuleId, final String downloadType, final String updateType) throws Exception {
return resultActions.andExpect(jsonPath("$.id", equalTo(String.valueOf(actionId))))
@@ -234,4 +245,92 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
return "attempt";
}
protected String getJsonRejectedCancelActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.REJECTED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("rejected"));
}
protected String getJsonRejectedDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.REJECTED, DdiResult.FinalResult.NONE,
Collections.singletonList("rejected"));
}
protected String getJsonDownloadDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.DOWNLOAD, DdiResult.FinalResult.NONE,
Collections.singletonList("download"));
}
protected String getJsonDownloadedDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.DOWNLOADED, DdiResult.FinalResult.NONE,
Collections.singletonList("download"));
}
protected String getJsonCanceledCancelActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CANCELED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("canceled"));
}
protected String getJsonCanceledDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CANCELED, DdiResult.FinalResult.NONE,
Collections.singletonList("canceled"));
}
protected String getJsonScheduledCancelActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("scheduled"));
}
protected String getJsonScheduledDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.NONE,
Collections.singletonList("scheduled"));
}
protected String getJsonResumedCancelActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.RESUMED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("resumed"));
}
protected String getJsonResumedDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.RESUMED, DdiResult.FinalResult.NONE,
Collections.singletonList("resumed"));
}
protected String getJsonProceedingCancelActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("proceeding"));
}
protected String getJsonProceedingDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE,
Collections.singletonList("proceeding"));
}
protected String getJsonClosedCancelActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("closed"));
}
protected String getJsonClosedDeploymentActionFeedback() throws JsonProcessingException {
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.NONE,
Collections.singletonList("closed"));
}
protected String getJsonActionFeedback(final DdiStatus.ExecutionStatus executionStatus,
final DdiResult.FinalResult finalResult) throws JsonProcessingException {
return getJsonActionFeedback(executionStatus, finalResult,
Collections.singletonList(RandomStringUtils.randomAlphanumeric(1000)));
}
protected String getJsonActionFeedback(final DdiStatus.ExecutionStatus executionStatus, final DdiResult ddiResult,
final List<String> messages) throws JsonProcessingException {
final DdiStatus ddiStatus = new DdiStatus(executionStatus, ddiResult, messages);
return objectMapper.writeValueAsString(new DdiActionFeedback(Instant.now().toString(), ddiStatus));
}
protected String getJsonActionFeedback(final DdiStatus.ExecutionStatus executionStatus,
final DdiResult.FinalResult finalResult, final List<String> messages) throws JsonProcessingException {
final DdiStatus ddiStatus = new DdiStatus(executionStatus, new DdiResult(finalResult, new DdiProgress(2, 5)),
messages);
return objectMapper.writeValueAsString(new DdiActionFeedback(Instant.now().toString(), ddiStatus));
}
}

View File

@@ -21,15 +21,17 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.hawkbit.ddi.json.model.DdiResult;
import org.eclipse.hawkbit.ddi.json.model.DdiStatus;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.jupiter.api.Test;
import org.springframework.hateoas.MediaTypes;
@@ -57,18 +59,22 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
final Action cancelAction = deploymentManagement.cancelAction(actionId);
// check that we can get the cancel action as CBOR
final byte[] result = mvc.perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId(), tenantAware.getCurrentTenant()).accept(DdiRestConstants.MEDIA_TYPE_CBOR))
final byte[] result = mvc
.perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId(), tenantAware.getCurrentTenant())
.accept(DdiRestConstants.MEDIA_TYPE_CBOR))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR))
.andReturn().getResponse().getContentAsByteArray();
assertThat(JsonPathUtils.<String>evaluate(cborToJson(result), "$.id")).isEqualTo(String.valueOf(cancelAction.getId()));
assertThat(JsonPathUtils.<String>evaluate(cborToJson(result), "$.cancelAction.stopId")).isEqualTo(String.valueOf(actionId));
.andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR)).andReturn().getResponse()
.getContentAsByteArray();
assertThat(JsonPathUtils.<String> evaluate(cborToJson(result), "$.id"))
.isEqualTo(String.valueOf(cancelAction.getId()));
assertThat(JsonPathUtils.<String> evaluate(cborToJson(result), "$.cancelAction.stopId"))
.isEqualTo(String.valueOf(actionId));
// and submit feedback as CBOR
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).content(
jsonToCbor(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "proceeding")))
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(jsonToCbor(getJsonProceedingCancelActionFeedback()))
.contentType(DdiRestConstants.MEDIA_TYPE_CBOR).accept(DdiRestConstants.MEDIA_TYPE_CBOR))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
}
@@ -85,11 +91,11 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
final Action cancelAction = deploymentManagement.cancelAction(actionId);
// controller rejects cancelation
// controller rejects cancellation
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "rejected"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonRejectedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
final long current = System.currentTimeMillis();
@@ -112,8 +118,9 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// and finish it
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/"
+ actionId + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed", "success"))
+ actionId + "/feedback", tenantAware.getCurrentTenant()).content(
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.NONE,
Collections.singletonList("message")))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
@@ -139,9 +146,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
final long timeBeforeFirstPoll = System.currentTimeMillis();
mvc.perform(get("/{tenant}/controller/v1/{controller}", tenantAware.getCurrentTenant(),
TestdataFactory.DEFAULT_CONTROLLER_ID).accept(MediaTypes.HAL_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
TestdataFactory.DEFAULT_CONTROLLER_ID).accept(MediaTypes.HAL_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
startsWith("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/"
@@ -191,8 +197,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// controller confirmed cancelled action, should not be active anymore
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON)
.content(JsonBuilder.cancelActionFeedback(actionId.toString(), "closed"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
activeActionsByTarget = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
@@ -263,8 +269,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "proceeding"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonProceedingCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
@@ -272,16 +278,16 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "resumed"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonResumedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(4);
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "scheduled"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonScheduledCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(5);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
@@ -290,8 +296,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "canceled"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonCanceledCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(6);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
@@ -303,8 +309,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "rejected"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonRejectedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(7);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
@@ -312,8 +318,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// update closed -> should remove the action from active
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(8);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).isEmpty();
@@ -364,8 +370,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// now lets return feedback for the first cancelation
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(7);
@@ -391,8 +397,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// now lets return feedback for the second cancelation
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction2.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction2.getId().toString(), "closed"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(9);
@@ -426,8 +432,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// now lets return feedback for the third cancelation
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction3.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction3.getId().toString(), "closed"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(13);
@@ -447,7 +453,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
final Action cancelAction = deploymentManagement.cancelAction(actionId);
final String feedback = JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "proceeding");
final String feedback = getJsonProceedingCancelActionFeedback();
// assignDistributionSet creates an ActionStatus and cancel action
// stores an action status, so
// only 97 action status left
@@ -473,8 +479,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// not allowed methods
mvc.perform(put("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
mvc.perform(delete("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
@@ -488,36 +494,35 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// bad content type
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed"))
.contentType(MediaType.APPLICATION_ATOM_XML).accept(MediaType.APPLICATION_JSON))
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_ATOM_XML)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isUnsupportedMediaType());
// bad body
String invalidFeedback = "{\"status\":{\"execution\":\"546456456\",\"result\":{\"finished\":\"none\",\"progress\":{\"cnt\":2,\"of\":5}},\"details\":\"none\"]}}";
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "546456456"))
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).content(invalidFeedback)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
// non existing target
mvc.perform(post("/{tenant}/controller/v1/12345/cancelAction/" + cancelAction.getId() + "/feedback",
tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed"))
tenantAware.getCurrentTenant()).content(getJsonClosedCancelActionFeedback())
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
// invalid action
invalidFeedback = "{\"id\":\"sdfsdfsdfs\",\"status\":{\"execution\":\"closed\",\"result\":{\"finished\":\"none\",\"progress\":{\"cnt\":2,\"of\":5}},\"details\":\"details\"]}}";
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback("sdfsdfsdfs", "closed"))
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).content(invalidFeedback)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
// finaly, get it right :)
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
}
}

View File

@@ -27,6 +27,8 @@ import java.util.stream.Collectors;
import org.apache.commons.lang3.RandomUtils;
import org.assertj.core.api.Condition;
import org.eclipse.hawkbit.ddi.json.model.DdiResult;
import org.eclipse.hawkbit.ddi.json.model.DdiStatus;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
@@ -45,7 +47,6 @@ import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.eclipse.hawkbit.rest.exception.MessageNotReadableException;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.PageRequest;
@@ -81,8 +82,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
.getContent().get(0);
// get deployment base
performGet(DEPLOYMENT_BASE,
MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), status().isOk(),
performGet(DEPLOYMENT_BASE, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), status().isOk(),
tenantAware.getCurrentTenant(), target.getControllerId(), action.getId().toString());
final Long softwareModuleId = distributionSet.getModules().stream().findAny().get().getId();
@@ -92,8 +92,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
status().isOk(), tenantAware.getCurrentTenant(), target.getControllerId(),
String.valueOf(softwareModuleId));
final byte[] feedback = jsonToCbor(
JsonBuilder.deploymentActionFeedback(action.getId().toString(), "proceeding"));
final byte[] feedback = jsonToCbor(getJsonProceedingDeploymentActionFeedback());
postDeploymentFeedback(MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), target.getControllerId(),
action.getId(), feedback, status().isOk());
@@ -164,8 +163,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
// Run test
final long current = System.currentTimeMillis();
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID)
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
DEFAULT_CONTROLLER_ID).andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString()))));
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery())
@@ -262,8 +260,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final long current = System.currentTimeMillis();
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID)
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
DEFAULT_CONTROLLER_ID).andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString()))));
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery())
@@ -274,9 +271,9 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final DistributionSet findDistributionSetByAction = distributionSetManagement.getByAction(action.getId()).get();
getAndVerifyDeploymentBasePayload(DEFAULT_CONTROLLER_ID, MediaType.APPLICATION_JSON, ds,
visibleMetadataOsKey, visibleMetadataOsValue, artifact, artifactSignature, action.getId(), "attempt",
"attempt", getOsModule(findDistributionSetByAction));
getAndVerifyDeploymentBasePayload(DEFAULT_CONTROLLER_ID, MediaType.APPLICATION_JSON, ds, visibleMetadataOsKey,
visibleMetadataOsValue, artifact, artifactSignature, action.getId(), "attempt", "attempt",
getOsModule(findDistributionSetByAction));
// Retrieved is reported
final List<ActionStatus> actionStatusMessages = deploymentManagement
@@ -301,8 +298,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final Target savedTarget = createTargetAndAssertNoActiveActions();
final List<Target> saved = assignDistributionSet(ds.getId(), savedTarget.getControllerId(),
ActionType.TIMEFORCED)
.getAssignedEntity().stream().map(Action::getTarget).collect(Collectors.toList());
ActionType.TIMEFORCED).getAssignedEntity().stream().map(Action::getTarget).collect(Collectors.toList());
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
@@ -321,8 +317,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final long current = System.currentTimeMillis();
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID)
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
DEFAULT_CONTROLLER_ID).andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString()))));
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery())
@@ -337,9 +332,9 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
artifactSignature, action.getId(),
findDistributionSetByAction.findFirstModuleByType(osType).get().getId(), "forced", "forced");
getAndVerifyDeploymentBasePayload(DEFAULT_CONTROLLER_ID, MediaTypes.HAL_JSON, ds, artifact,
artifactSignature, action.getId(),
findDistributionSetByAction.findFirstModuleByType(osType).get().getId(), "forced", "forced");
getAndVerifyDeploymentBasePayload(DEFAULT_CONTROLLER_ID, MediaTypes.HAL_JSON, ds, artifact, artifactSignature,
action.getId(), findDistributionSetByAction.findFirstModuleByType(osType).get().getId(), "forced",
"forced");
// Retrieved is reported
final Iterable<ActionStatus> actionStatusMessages = deploymentManagement
@@ -368,8 +363,8 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final Target savedTarget = createTargetAndAssertNoActiveActions();
final List<Target> saved = assignDistributionSet(ds.getId(), savedTarget.getControllerId(),
ActionType.DOWNLOAD_ONLY)
.getAssignedEntity().stream().map(Action::getTarget).collect(Collectors.toList());
ActionType.DOWNLOAD_ONLY).getAssignedEntity().stream().map(Action::getTarget)
.collect(Collectors.toList());
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
@@ -388,8 +383,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final long current = System.currentTimeMillis();
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID)
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
DEFAULT_CONTROLLER_ID).andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString()))));
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery())
@@ -472,7 +466,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0);
final String feedback = JsonBuilder.deploymentActionFeedback(action.getId().toString(), "proceeding");
final String feedback = getJsonProceedingDeploymentActionFeedback();
// assign distribution set creates an action status, so only 99 left
for (int i = 0; i < 99; i++) {
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action.getId(), feedback, status().isOk());
@@ -497,10 +491,9 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
messages.add(String.valueOf(i));
}
final String feedback = JsonBuilder.deploymentActionFeedback(action.getId().toString(), "proceeding", "none",
final String feedback = getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE,
messages);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action.getId(), feedback,
status().isForbidden());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action.getId(), feedback, status().isForbidden());
}
@Test
@@ -522,22 +515,22 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assertThat(targetManagement.findByUpdateStatus(PageRequest.of(0, 10), TargetUpdateStatus.UNKNOWN)).hasSize(2);
// action1 done
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId1,
JsonBuilder.deploymentActionFeedback(actionId1.toString(), "closed"), status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId1, getJsonClosedDeploymentActionFeedback(),
status().isOk());
findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.PENDING, 2, Optional.of(ds1));
assertStatusMessagesCount(4);
// action2 done
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId2,
JsonBuilder.deploymentActionFeedback(actionId2.toString(), "closed"), status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId2, getJsonClosedDeploymentActionFeedback(),
status().isOk());
findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.PENDING, 1, Optional.of(ds2));
assertStatusMessagesCount(5);
// action3 done
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId3,
JsonBuilder.deploymentActionFeedback(actionId3.toString(), "closed"), status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId3, getJsonClosedDeploymentActionFeedback(),
status().isOk());
findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.IN_SYNC, 0, Optional.of(ds3));
assertStatusMessagesCount(6);
@@ -556,7 +549,8 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final Action action = deploymentManagement.findActionsByDistributionSet(PAGE, ds.getId()).getContent().get(0);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action.getId(),
JsonBuilder.deploymentActionFeedback(action.getId().toString(), "closed", "failure", "error message"),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.FAILURE,
Collections.singletonList("Error message")),
status().isOk());
findTargetAndAssertUpdateStatus(Optional.empty(), TargetUpdateStatus.ERROR, 0, Optional.empty());
@@ -569,8 +563,8 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
Collections.singletonList(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get()));
final Action action2 = deploymentManagement.findActiveActionsByTarget(PAGE, DEFAULT_CONTROLLER_ID).getContent()
.get(0);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action2.getId(),
JsonBuilder.deploymentActionFeedback(action2.getId().toString(), "closed", "SUCCESS"), status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action2.getId(), getJsonClosedCancelActionFeedback(),
status().isOk());
findTargetAndAssertUpdateStatus(Optional.of(ds), TargetUpdateStatus.IN_SYNC, 0, Optional.of(ds));
assertTargetCountByStatus(0, 0, 1);
assertThat(deploymentManagement.findInActiveActionsByTarget(PAGE, DEFAULT_CONTROLLER_ID)).hasSize(2);
@@ -592,33 +586,33 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
// Now valid Feedback
for (int i = 0; i < 4; i++) {
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "proceeding"), status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonProceedingDeploymentActionFeedback(),
status().isOk());
assertActionStatusCount(i + 2, i);
}
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "scheduled"), status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonScheduledDeploymentActionFeedback(),
status().isOk());
assertActionStatusCount(6, 5);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "resumed"), status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonResumedDeploymentActionFeedback(),
status().isOk());
assertActionStatusCount(7, 6);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "canceled"), status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonCanceledDeploymentActionFeedback(),
status().isOk());
assertStatusAndActiveActionsCount(TargetUpdateStatus.PENDING, 1);
assertActionStatusCount(8, 7, 0, 0, 1);
assertTargetCountByStatus(1, 0, 0);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "rejected"), status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonRejectedDeploymentActionFeedback(),
status().isOk());
assertStatusAndActiveActionsCount(TargetUpdateStatus.PENDING, 1);
assertActionStatusCount(9, 6, 1, 0, 1);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed"), status().isOk());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonClosedDeploymentActionFeedback(),
status().isOk());
assertStatusAndActiveActionsCount(TargetUpdateStatus.IN_SYNC, 0);
assertActionStatusCount(10, 7, 1, 1, 1);
assertTargetCountByStatus(0, 0, 1);
@@ -635,14 +629,13 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
// target does not exist
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, 1234L,
JsonBuilder.deploymentActionInProgressFeedback("1234"), status().isNotFound());
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, 1234L, getJsonProceedingDeploymentActionFeedback(),
status().isNotFound());
final Target savedTarget = testdataFactory.createTarget(DEFAULT_CONTROLLER_ID);
// Action does not exist
postDeploymentFeedback("4713", 1234L, JsonBuilder.deploymentActionInProgressFeedback("1234"),
status().isNotFound());
postDeploymentFeedback("4713", 1234L, getJsonProceedingDeploymentActionFeedback(), status().isNotFound());
assignDistributionSet(savedSet, Collections.singletonList(savedTarget)).getAssignedEntity().iterator().next();
assignDistributionSet(savedSet2, Collections.singletonList(testdataFactory.createTarget("4713")));
@@ -651,8 +644,8 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
.getContent().get(0);
// action exists but is not assigned to this target
postDeploymentFeedback("4713", updateAction.getId(),
JsonBuilder.deploymentActionInProgressFeedback(updateAction.getId().toString()), status().isNotFound());
postDeploymentFeedback("4713", updateAction.getId(), getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING,
DdiResult.FinalResult.NONE, Collections.singletonList("")), status().isNotFound());
// not allowed methods
mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(),
@@ -669,11 +662,11 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Ensures that an invalid id in feedback body returns a bad request.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1)})
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1) })
public void invalidIdInFeedbackReturnsBadRequest() throws Exception {
final Target target = testdataFactory.createTarget("1080");
final DistributionSet ds = testdataFactory.createDistributionSet("");
@@ -681,17 +674,17 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds.getId(), "1080");
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0);
postDeploymentFeedback("1080", action.getId(),
JsonBuilder.deploymentActionInProgressFeedback("AAAA"), status().isBadRequest());
final String invalidFeedback = "{\"id\":\"AAAA\",\"status\":{\"execution\":\"proceeding\",\"result\":{\"finished\":\"none\",\"progress\":{\"cnt\":2,\"of\":5}},\"details\":\"details\"]}}";
postDeploymentFeedback("1080", action.getId(), invalidFeedback, status().isBadRequest());
}
@Test
@Description("Ensures that a missing feedback result in feedback body returns a bad request.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1)})
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1) })
public void missingResultAttributeInFeedbackReturnsBadRequest() throws Exception {
final Target target = testdataFactory.createTarget("1080");
@@ -700,20 +693,21 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds.getId(), "1080");
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0);
final String missingResultInFeedback = JsonBuilder.missingResultInFeedback(action.getId().toString(), "closed",
"test");
postDeploymentFeedback("1080", action.getId(), missingResultInFeedback,
status().isBadRequest()).andExpect(jsonPath("$.*", hasSize(3))).andExpect(
jsonPath("$.exceptionClass", equalTo(MessageNotReadableException.class.getCanonicalName())));
final String missingResultInFeedback = getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, (DdiResult) null,
Collections.singletonList("test"));
postDeploymentFeedback("1080", action.getId(), missingResultInFeedback, status().isBadRequest())
.andExpect(jsonPath("$.*", hasSize(3)))
.andExpect(jsonPath("$.exceptionClass", equalTo(MessageNotReadableException.class.getCanonicalName())));
}
@Test
@Description("Ensures that a missing finished result in feedback body returns a bad request.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1)})
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1) })
public void missingFinishedAttributeInFeedbackReturnsBadRequest() throws Exception {
final Target target = testdataFactory.createTarget("1080");
@@ -722,11 +716,13 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0);
final String missingFinishedResultInFeedback = JsonBuilder
.missingFinishedResultInFeedback(action.getId().toString(), "closed", "test");
postDeploymentFeedback("1080", action.getId(), missingFinishedResultInFeedback,
status().isBadRequest()).andExpect(jsonPath("$.*", hasSize(3))).andExpect(
jsonPath("$.exceptionClass", equalTo(MessageNotReadableException.class.getCanonicalName())));
final String missingFinishedResultInFeedback = getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED,
new DdiResult(null, null),
Collections.singletonList("test"));
postDeploymentFeedback("1080", action.getId(), missingFinishedResultInFeedback, status().isBadRequest())
.andExpect(jsonPath("$.*", hasSize(3)))
.andExpect(jsonPath("$.exceptionClass", equalTo(MessageNotReadableException.class.getCanonicalName())));
}
private void assertActionStatusCount(final int actionStatusCount, final int minActionStatusCountInPage) {

View File

@@ -27,6 +27,8 @@ import java.util.List;
import java.util.stream.Stream;
import org.apache.commons.lang3.RandomUtils;
import org.eclipse.hawkbit.ddi.json.model.DdiResult;
import org.eclipse.hawkbit.ddi.json.model.DdiStatus;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
@@ -45,7 +47,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -77,8 +78,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Target target = testdataFactory.createTarget();
final DistributionSet ds = testdataFactory.createDistributionSet("");
final Long actionId = getFirstAssignedActionId(assignDistributionSet(ds, target));
postDeploymentFeedback(target.getControllerId(), actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed"), status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId, getJsonClosedDeploymentActionFeedback(),
status().isOk());
// get installed base
performGet(INSTALLED_BASE, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), status().isOk(),
@@ -123,7 +124,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
actionId1, ds1.findFirstModuleByType(osType).get().getId(), Action.ActionType.SOFT);
postDeploymentFeedback(target.getControllerId(), actionId1,
JsonBuilder.deploymentActionFeedback(actionId1.toString(), "closed", "success", "Closed"),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Closed")),
status().isOk());
getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds1, artifact1, artifactSignature1,
@@ -143,7 +145,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
actionId2, ds2.findFirstModuleByType(osType).get().getId(), Action.ActionType.FORCED);
postDeploymentFeedback(target.getControllerId(), actionId2,
JsonBuilder.deploymentActionFeedback(actionId2.toString(), "closed", "success", "Closed"),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Closed")),
status().isOk());
getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds2, artifact2, artifactSignature2,
@@ -155,7 +158,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
startsWith(installedBaseLink(CONTROLLER_ID, actionId2.toString()))))
.andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist());
// older installed action is still accessible, although not part of controller base
// older installed action is still accessible, although not part of controller
// base
getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds1, artifact1, artifactSignature1,
actionId1, ds1.findFirstModuleByType(osType).get().getId(), Action.ActionType.SOFT);
}
@@ -177,20 +181,25 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
deploymentManagement.cancelAction(actionId1);
postCancelFeedback(target.getControllerId(), actionId1,
JsonBuilder.cancelActionFeedback(actionId1.toString(), "closed", "Canceled"), status().isOk());
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
status().isOk());
// assign ds1, action2 - and provide cancel feedback
final Long actionId2 = getFirstAssignedActionId(
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.FORCED));
deploymentManagement.cancelAction(actionId2);
postCancelFeedback(target.getControllerId(), actionId2,
JsonBuilder.cancelActionFeedback(actionId2.toString(), "closed", "Canceled"), status().isOk());
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
status().isOk());
// assign ds1, action 3 - and provide success feedback
final Long actionId3 = getFirstAssignedActionId(
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
postDeploymentFeedback(target.getControllerId(), actionId3,
JsonBuilder.deploymentActionFeedback(actionId3.toString(), "closed", "success", "Closed"),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
status().isOk());
// Test: latest succeeded action is returned in installedBase
@@ -228,7 +237,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Long actionId1 = getFirstAssignedActionId(
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
postDeploymentFeedback(target.getControllerId(), actionId1,
JsonBuilder.deploymentActionFeedback(actionId1.toString(), "closed", "success", "Success"),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Success")),
status().isOk());
// assign ds2, action2 - assign ds1, action 3 - and cancel both
@@ -238,10 +248,14 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
deploymentManagement.cancelAction(actionId2);
postCancelFeedback(target.getControllerId(), actionId2,
JsonBuilder.cancelActionFeedback(actionId2.toString(), "closed", "Canceled"), status().isOk());
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
status().isOk());
deploymentManagement.cancelAction(actionId3);
postCancelFeedback(target.getControllerId(), actionId3,
JsonBuilder.cancelActionFeedback(actionId3.toString(), "closed", "Canceled"), status().isOk());
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
status().isOk());
// Test: the succeeded action is returned in installedBase instead of the latest
// cancelled action
@@ -279,7 +293,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Long actionId1 = getFirstAssignedActionId(
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
postDeploymentFeedback(target.getControllerId(), actionId1,
JsonBuilder.deploymentActionFeedback(actionId1.toString(), "closed", "success", "Success"),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Success")),
status().isOk());
// assign ds2, action2 - assign ds1, action 3 - and cancel action 2
@@ -289,7 +304,9 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
deploymentManagement.cancelAction(actionId2);
postCancelFeedback(target.getControllerId(), actionId2,
JsonBuilder.cancelActionFeedback(actionId2.toString(), "closed", "Canceled"), status().isOk());
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
status().isOk());
// Test: the succeeded action is returned in installedBase instead of the latest
// cancelled action
@@ -338,8 +355,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final DistributionSet ds = testdataFactory.createDistributionSet("");
final Long actionId = getFirstAssignedActionId(assignDistributionSet(ds, target));
postDeploymentFeedback(target.getControllerId(), actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed"), status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId, getJsonClosedDeploymentActionFeedback(),
status().isOk());
final Long softwareModuleId = ds.getModules().stream().findAny().get().getId();
performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isOk(),
@@ -385,7 +402,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds.getId(), target.getControllerId(), actionType));
postDeploymentFeedback(target.getControllerId(), actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed", "success", "Closed"),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Closed")),
status().isOk());
// Run test
@@ -433,10 +451,10 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
.andExpect(jsonPath("$._links.deploymentBase.href").exists())
.andExpect(jsonPath("$._links.installedBase.href").doesNotExist());
postDeploymentFeedback(target.getControllerId(), actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "download"), status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "downloaded"), status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId, getJsonDownloadDeploymentActionFeedback(),
status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId, getJsonDownloadedDeploymentActionFeedback(),
status().isOk());
// Test
performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(),
@@ -448,7 +466,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
@ParameterizedTest
@MethodSource("org.eclipse.hawkbit.ddi.rest.resource.DdiInstalledBaseTest#actionTypeForDeployment")
@Description("Test a failed deployment to a controller. Checks that closed action is not represented as installedBase.")
public void deploymentActionFailedNotInInstalledBase(Action.ActionType actionType) throws Exception {
public void deploymentActionFailedNotInInstalledBase(final Action.ActionType actionType) throws Exception {
// Prepare test data
final Target target = testdataFactory.createTarget();
final DistributionSet ds = testdataFactory.createDistributionSet("");
@@ -461,9 +479,11 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
.andExpect(jsonPath("$._links.installedBase.href").doesNotExist());
postDeploymentFeedback(target.getControllerId(), actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "proceeding"), status().isOk());
getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE),
status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed", "failure", "Installation failed"),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.FAILURE,
Collections.singletonList("Installation failed")),
status().isOk());
// Test
@@ -482,14 +502,20 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(), JsonBuilder.deploymentActionFeedback(
savedAction.getId().toString(), "scheduled", "Installation scheduled"), status().isOk());
postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(),
getJsonActionFeedback(DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.NONE,
Collections.singletonList("Installation scheduled")),
status().isOk());
postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(), JsonBuilder.deploymentActionFeedback(
savedAction.getId().toString(), "proceeding", "Installation proceeding"), status().isOk());
postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(),
getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE,
Collections.singletonList("Installation proceeding")),
status().isOk());
// only this feedback triggers the ActionUpdateEvent
postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(), JsonBuilder.deploymentActionFeedback(
savedAction.getId().toString(), "closed", "success", "Installation completed"), status().isOk());
postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(),
getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Installation completed")),
status().isOk());
// Test
// for zero input no action history is returned
@@ -545,8 +571,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final DistributionSet savedSet = testdataFactory.createDistributionSet("");
final Long actionId = getFirstAssignedActionId(assignDistributionSet(savedSet, toAssign));
postDeploymentFeedback(CONTROLLER_ID, actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed", "success"), status().isOk());
postDeploymentFeedback(CONTROLLER_ID, actionId, getJsonClosedCancelActionFeedback(), status().isOk());
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, actionId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, actionId)

View File

@@ -33,6 +33,8 @@ import java.util.Map;
import java.util.UUID;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.ddi.json.model.DdiResult;
import org.eclipse.hawkbit.ddi.json.model.DdiStatus;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
@@ -88,9 +90,9 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Test
@Description("Ensure that the root poll resource is available as CBOR")
void rootPollResourceCbor() throws Exception {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711)
.accept(DdiRestConstants.MEDIA_TYPE_CBOR)).andDo(MockMvcResultPrinter.print())
.andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR)).andExpect(status().isOk());
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711).accept(DdiRestConstants.MEDIA_TYPE_CBOR))
.andDo(MockMvcResultPrinter.print()).andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR))
.andExpect(status().isOk());
}
@Test
@@ -147,11 +149,12 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
// make a poll, audit information should not be changed, run as
// controller principal!
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownTargetControllerId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
return null;
});
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS),
() -> {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownTargetControllerId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
return null;
});
// verify that audit information has not changed
final Target targetVerify = targetManagement.getByControllerID(knownTargetControllerId).get();
@@ -175,7 +178,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
void rootRsPlugAndPlay() throws Exception {
final long current = System.currentTimeMillis();
String controllerId = "4711";
final String controllerId = "4711";
mvc.perform(get(CONTROLLER_BASE, "default-tenant", controllerId)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaTypes.HAL_JSON))
@@ -204,16 +207,16 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Expect(type = TargetPollEvent.class, count = 1),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void pollWithModifiedGlobalPollingTime() throws Exception {
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withUser("tenantadmin", HAS_AUTH_TENANT_CONFIGURATION), () -> {
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
"00:02:00");
return null;
});
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withUser("tenantadmin", HAS_AUTH_TENANT_CONFIGURATION),
() -> {
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
"00:02:00");
return null;
});
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withUser("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:02:00")));
return null;
});
@@ -230,7 +233,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6) })
void rootRsNotModified() throws Exception {
String controllerId = "4711";
final String controllerId = "4711";
final String etag = mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
@@ -308,7 +311,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
void rootRsPrecommissioned() throws Exception {
String controllerId = "4711";
final String controllerId = "4711";
testdataFactory.createTarget(controllerId);
assertThat(targetManagement.getByControllerID(controllerId).get().getUpdateStatus())
@@ -339,12 +342,12 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
final long create = System.currentTimeMillis();
// make a poll, audit information should be set on plug and play
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
mvc.perform(
get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownControllerId1))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
return null;
});
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS),
() -> {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownControllerId1))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
return null;
});
// verify
final Target target = targetManagement.getByControllerID(knownControllerId1).get();
@@ -414,9 +417,8 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
final Map<String, String> attributes = Collections.singletonMap("AttributeKey", "AttributeValue");
assertThatAttributesUpdateIsRequested(savedTarget.getControllerId());
mvc.perform(put(CONTROLLER_BASE + "/configData", tenantAware.getCurrentTenant(),
savedTarget.getControllerId()).content(JsonBuilder.configData(attributes).toString())
.contentType(MediaType.APPLICATION_JSON))
mvc.perform(put(CONTROLLER_BASE + "/configData", tenantAware.getCurrentTenant(), savedTarget.getControllerId())
.content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
assertThatAttributesUpdateIsNotRequested(savedTarget.getControllerId());
@@ -465,8 +467,9 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
if (message == null) {
message = RandomStringUtils.randomAlphanumeric(1000);
}
final String feedback = JsonBuilder.deploymentActionFeedback(action.getId().toString(), execution, finished,
message);
final String feedback = getJsonActionFeedback(DdiStatus.ExecutionStatus.valueOf(execution.toUpperCase()),
DdiResult.FinalResult.valueOf(finished.toUpperCase()), Collections.singletonList(message));
return mvc.perform(
post(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(), target.getControllerId(), action.getId())
.content(feedback).contentType(MediaType.APPLICATION_JSON));
@@ -503,8 +506,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=2", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages",
hasItem(containsString(TARGET_COMPLETED_INSTALLATION_MSG))))
@@ -540,8 +542,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=0", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages").doesNotExist());
@@ -577,8 +578,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=-1", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages",
hasItem(containsString(TARGET_SCHEDULED_INSTALLATION_MSG))))
@@ -593,13 +593,14 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
void sleepTimeResponseForDifferentMaintenanceWindowParameters() throws Exception {
final DistributionSet ds = testdataFactory.createDistributionSet("");
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withUser("tenantadmin", HAS_AUTH_TENANT_CONFIGURATION), () -> {
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
"00:05:00");
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.MIN_POLLING_TIME_INTERVAL,
"00:01:00");
return null;
});
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withUser("tenantadmin", HAS_AUTH_TENANT_CONFIGURATION),
() -> {
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
"00:05:00");
tenantConfigurationManagement
.addOrUpdateConfiguration(TenantConfigurationKey.MIN_POLLING_TIME_INTERVAL, "00:01:00");
return null;
});
final Target savedTarget = testdataFactory.createTarget("1911");
assignDistributionSetWithMaintenanceWindow(ds.getId(), savedTarget.getControllerId(), getTestSchedule(16),
@@ -648,9 +649,9 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "1911",
action.getId()).accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.deployment.download", equalTo("forced")))
mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "1911", action.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.deployment.download", equalTo("forced")))
.andExpect(jsonPath("$.deployment.update", equalTo("skip")))
.andExpect(jsonPath("$.deployment.maintenanceWindow", equalTo("unavailable")));
}
@@ -668,9 +669,9 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0);
mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "1911",
action.getId()).accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.deployment.download", equalTo("forced")))
mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "1911", action.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.deployment.download", equalTo("forced")))
.andExpect(jsonPath("$.deployment.update", equalTo("forced")))
.andExpect(jsonPath("$.deployment.maintenanceWindow", equalTo("available")));
}
@@ -704,8 +705,9 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
throws Exception {
final String expectedDeploymentBaseLink = String.format("/%s/controller/v1/%s/deploymentBase/%d",
tenantAware.getCurrentTenant(), controllerId, expectedActionId);
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
mvc.perform(
get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$._links.deploymentBase.href", containsString(expectedDeploymentBaseLink)));
}

View File

@@ -19,7 +19,6 @@ import java.util.List;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.security.DosFilter;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
@@ -114,7 +113,7 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest {
@Description("Ensures that a WRITE DoS attempt is blocked ")
void putPostFloddingAttackThatisPrevented() throws Exception {
final Long actionId = prepareDeploymentBase();
final String feedback = JsonBuilder.deploymentActionFeedback(actionId.toString(), "proceeding");
final String feedback = getJsonProceedingDeploymentActionFeedback();
MvcResult result = null;
int requests = 0;
@@ -139,7 +138,7 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest {
@SuppressWarnings("squid:S2925") // No idea how to get rid of the Thread.sleep here
void acceptablePutPostLoad() throws Exception {
final Long actionId = prepareDeploymentBase();
final String feedback = JsonBuilder.deploymentActionFeedback(actionId.toString(), "proceeding");
final String feedback = getJsonProceedingDeploymentActionFeedback();
for (int x = 0; x < 5; x++) {
// sleep for one second

View File

@@ -11,19 +11,15 @@
hawkbit.controller.pollingTime=00:01:00
hawkbit.controller.pollingOverdueTime=00:01:00
hawkbit.controller.minPollingTime=00:00:30
hawkbit.controller.maintenanceWindowPollCount=3
# DDI configuration - END
# Upload configuration - START
spring.servlet.multipart.max-file-size=5MB
# Upload configuration - END
# Quota - START
hawkbit.server.security.dos.maxStatusEntriesPerAction=100
hawkbit.server.security.dos.maxAttributeEntriesPerTarget=10
# Quota - END
# Logging START - activate to see request/response details
#logging.level.org.eclipse.hawkbit.rest.util.MockMvcResultPrinter=DEBUG
# Logging END

View File

@@ -73,14 +73,14 @@ public interface MgmtDistributionSetTagRestApi {
ResponseEntity<MgmtTag> getDistributionSetTag(@PathVariable("distributionsetTagId") Long distributionsetTagId);
/**
* Handles the POST request of creating new distribution set tag. The
* request body must always be a list of tags.
* Handles the POST request of creating new distribution set tag. The request
* body must always be a list of tags.
*
* @param tags
* the distribution set tags to be created.
* @return In case all modules could successful created the ResponseEntity
* with status code 201 - Created. The Response Body are the created
* distribution set tags but without ResponseBody.
* @return In case all modules could successful created the ResponseEntity with
* status code 201 - Created. The Response Body contains the created
* distribution set tags but without details.
*/
@PostMapping(consumes = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
@@ -93,9 +93,9 @@ public interface MgmtDistributionSetTagRestApi {
* @param distributionsetTagId
* the ID of the distribution set tag
* @param restDSTagRest
* the the request body to be updated
* @return status OK if update is successful and the updated distribution
* set tag.
* the request body to be updated
* @return status OK if update is successful and the updated distribution set
* tag.
*/
@PutMapping(value = "/{distributionsetTagId}", consumes = { MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE,
@@ -144,26 +144,6 @@ public interface MgmtDistributionSetTagRestApi {
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) String sortParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) String rsqlParam);
/**
* Handles the GET request of retrieving all assigned distribution sets by
* the given tag id.
*
* @param distributionsetTagId
* the ID of the distribution set tag
*
* @return the list of assigned distribution sets.
*
* @deprecated please use
* {@link #getAssignedDistributionSets(Long, int, int, String, String)}
* instead as this variant does not include paging and as result
* returns only a limited list of distributionsets
*/
@Deprecated
@GetMapping(value = MgmtRestConstants.DEPRECATED_DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING, produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<List<MgmtDistributionSet>> getAssignedDistributionSets(
@PathVariable("distributionsetTagId") Long distributionsetTagId);
/**
* Handles the POST request to toggle the assignment of distribution sets by
* the given tag id.
@@ -182,28 +162,6 @@ public interface MgmtDistributionSetTagRestApi {
@PathVariable("distributionsetTagId") Long distributionsetTagId,
List<MgmtAssignedDistributionSetRequestBody> assignedDSRequestBodies);
/**
* Handles the POST request to toggle the assignment of distribution sets by
* the given tag id.
*
* @param distributionsetTagId
* the ID of the distribution set tag to retrieve
* @param assignedDSRequestBodies
* list of distribution set ids to be toggled
*
* @return the list of assigned distribution sets and unassigned
* distribution sets.
*
* @deprecated please use
* {@link MgmtDistributionSetTagRestApi#toggleTagAssignment}
*/
@Deprecated
@PostMapping(value = MgmtRestConstants.DEPRECATED_DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING
+ "/toggleTagAssignment")
ResponseEntity<MgmtDistributionSetTagAssigmentResult> toggleTagAssignmentUnpaged(
@PathVariable("distributionsetTagId") Long distributionsetTagId,
List<MgmtAssignedDistributionSetRequestBody> assignedDSRequestBodies);
/**
* Handles the POST request to assign distribution sets to the given tag id.
*
@@ -221,27 +179,6 @@ public interface MgmtDistributionSetTagRestApi {
@PathVariable("distributionsetTagId") Long distributionsetTagId,
List<MgmtAssignedDistributionSetRequestBody> assignedDSRequestBodies);
/**
* Handles the POST request to assign distribution sets to the given tag id.
*
* @param distributionsetTagId
* the ID of the distribution set tag to retrieve
* @param assignedDSRequestBodies
* list of distribution sets ids to be assigned
*
* @return the list of assigned distribution set.
*
* @deprecated please use
* {@link MgmtDistributionSetTagRestApi#assignDistributionSets}
*/
@Deprecated
@PostMapping(value = MgmtRestConstants.DEPRECATED_DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING, consumes = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<List<MgmtDistributionSet>> assignDistributionSetsUnpaged(
@PathVariable("distributionsetTagId") Long distributionsetTagId,
List<MgmtAssignedDistributionSetRequestBody> assignedDSRequestBodies);
/**
* Handles the DELETE request to unassign one distribution set from the
* given tag id.
@@ -257,22 +194,4 @@ public interface MgmtDistributionSetTagRestApi {
ResponseEntity<Void> unassignDistributionSet(@PathVariable("distributionsetTagId") Long distributionsetTagId,
@PathVariable("distributionsetId") Long distributionsetId);
/**
* Handles the DELETE request to unassign one distribution set from the
* given tag id.
*
* @param distributionsetTagId
* the ID of the distribution set tag
* @param distributionsetId
* the ID of the distribution set to unassign
* @return http status code
*
* @deprecated please use
* {@link MgmtDistributionSetTagRestApi#unassignDistributionSet}
*/
@Deprecated
@DeleteMapping(value = MgmtRestConstants.DEPRECATED_DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING
+ "/{distributionsetId}")
ResponseEntity<Void> unassignDistributionSetUnpaged(@PathVariable("distributionsetTagId") Long distributionsetTagId,
@PathVariable("distributionsetId") Long distributionsetId);
}

View File

@@ -119,15 +119,6 @@ public final class MgmtRestConstants {
*/
public static final String TARGETTYPE_V1_DS_TYPES = "compatibledistributionsettypes";
/**
* The tag URL mapping rest resource.
*
* @deprecated {@link #TARGET_TAG_TARGETS_REQUEST_MAPPING} is preferred as
* this resource on GET supports paging
*/
@Deprecated
public static final String DEPRECATAED_TARGET_TAG_TARGETS_REQUEST_MAPPING = "/{targetTagId}/targets";
/**
* The tag URL mapping rest resource.
*/
@@ -144,15 +135,6 @@ public final class MgmtRestConstants {
*/
public static final String TARGET_FILTER_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/targetfilters";
/**
* The deprecated tag URL mapping rest resource.
*
* @deprecated {@link #DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING}
* is preferred as this resource on GET supports paging
*/
@Deprecated
public static final String DEPRECATED_DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING = "/{distributionsetTagId}/distributionsets";
/**
* The tag URL mapping rest resource.
*/

View File

@@ -112,25 +112,6 @@ public interface MgmtTargetTagRestApi {
@DeleteMapping(value = "/{targetTagId}")
ResponseEntity<Void> deleteTargetTag(@PathVariable("targetTagId") Long targetTagId);
/**
* Handles the GET request of retrieving all assigned targets by the given
* tag id.
*
* @param targetTagId
* the ID of the target tag to retrieve
*
* @return the list of assigned targets.
*
* @deprecated please use
* {@link #getAssignedTargets(Long, int, int, String, String)}
* instead as this variant does not include paging and as result
* returns only a limited list of targets
*/
@Deprecated
@GetMapping(value = MgmtRestConstants.DEPRECATAED_TARGET_TAG_TARGETS_REQUEST_MAPPING, produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<List<MgmtTarget>> getAssignedTargets(@PathVariable("targetTagId") Long targetTagId);
/**
* Handles the GET request of retrieving all assigned targets by the given
* tag id.
@@ -177,27 +158,6 @@ public interface MgmtTargetTagRestApi {
ResponseEntity<MgmtTargetTagAssigmentResult> toggleTagAssignment(@PathVariable("targetTagId") Long targetTagId,
List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies);
/**
* Handles the POST request to toggle the assignment of targets by the given
* tag id.
*
* @param targetTagId
* the ID of the target tag to retrieve
* @param assignedTargetRequestBodies
* list of controller ids to be toggled
*
* @return the list of assigned targets and unassigned targets.
* @deprecated please use {@link MgmtTargetTagRestApi#toggleTagAssignment}
*/
@Deprecated
@PostMapping(value = MgmtRestConstants.DEPRECATAED_TARGET_TAG_TARGETS_REQUEST_MAPPING
+ "/toggleTagAssignment", consumes = { MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtTargetTagAssigmentResult> toggleTagAssignmentUnpaged(
@PathVariable("targetTagId") Long targetTagId,
List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies);
/**
* Handles the POST request to assign targets to the given tag id.
*
@@ -214,25 +174,6 @@ public interface MgmtTargetTagRestApi {
ResponseEntity<List<MgmtTarget>> assignTargets(@PathVariable("targetTagId") Long targetTagId,
List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies);
/**
* Handles the POST request to assign targets to the given tag id.
*
* @param targetTagId
* the ID of the target tag to retrieve
* @param assignedTargetRequestBodies
* list of controller ids to be assigned
*
* @return the list of assigned targets.
*
* @deprecated please use {@link MgmtTargetTagRestApi#assignTargets}
*/
@Deprecated
@PostMapping(value = MgmtRestConstants.DEPRECATAED_TARGET_TAG_TARGETS_REQUEST_MAPPING, consumes = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<List<MgmtTarget>> assignTargetsUnpaged(@PathVariable("targetTagId") Long targetTagId,
List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies);
/**
* Handles the DELETE request to unassign one target from the given tag id.
*
@@ -245,20 +186,4 @@ public interface MgmtTargetTagRestApi {
@DeleteMapping(value = MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING + "/{controllerId}")
ResponseEntity<Void> unassignTarget(@PathVariable("targetTagId") Long targetTagId,
@PathVariable("controllerId") String controllerId);
/**
* Handles the DELETE request to unassign one target from the given tag id.
*
* @param targetTagId
* the ID of the target tag
* @param controllerId
* the ID of the target to unassign
* @return http status code
*
* @deprecated please use {@link MgmtTargetTagRestApi#unassignTarget}
*/
@Deprecated
@DeleteMapping(value = MgmtRestConstants.DEPRECATAED_TARGET_TAG_TARGETS_REQUEST_MAPPING + "/{controllerId}")
ResponseEntity<Void> unassignTargetUnpaged(@PathVariable("targetTagId") Long targetTagId,
@PathVariable("controllerId") String controllerId);
}

View File

@@ -30,7 +30,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
@@ -139,15 +138,6 @@ public class MgmtDistributionSetTagResource implements MgmtDistributionSetTagRes
return ResponseEntity.ok().build();
}
@Override
public ResponseEntity<List<MgmtDistributionSet>> getAssignedDistributionSets(
@PathVariable("distributionsetTagId") final Long distributionsetTagId) {
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDistributionSets(distributionSetManagement
.findByTag(PageRequest.of(0, MgmtRestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT),
distributionsetTagId)
.getContent()));
}
@Override
public ResponseEntity<PagedList<MgmtDistributionSet>> getAssignedDistributionSets(
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
@@ -204,7 +194,7 @@ public class MgmtDistributionSetTagResource implements MgmtDistributionSetTagRes
LOG.debug("Assign DistributionSet {} for ds tag {}", assignedDSRequestBodies.size(), distributionsetTagId);
final List<DistributionSet> assignedDs = this.distributionSetManagement
.assignTag(findDistributionSetIds(assignedDSRequestBodies), distributionsetTagId);
LOG.debug("Assignd DistributionSet {}", assignedDs.size());
LOG.debug("Assigned DistributionSet {}", assignedDs.size());
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDistributionSets(assignedDs));
}
@@ -227,26 +217,4 @@ public class MgmtDistributionSetTagResource implements MgmtDistributionSetTagRes
return assignedDistributionSetRequestBodies.stream()
.map(MgmtAssignedDistributionSetRequestBody::getDistributionSetId).collect(Collectors.toList());
}
@Override
public ResponseEntity<MgmtDistributionSetTagAssigmentResult> toggleTagAssignmentUnpaged(
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
@RequestBody final List<MgmtAssignedDistributionSetRequestBody> assignedDSRequestBodies) {
return toggleTagAssignment(distributionsetTagId, assignedDSRequestBodies);
}
@Override
public ResponseEntity<List<MgmtDistributionSet>> assignDistributionSetsUnpaged(
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
@RequestBody final List<MgmtAssignedDistributionSetRequestBody> assignedDSRequestBodies) {
return assignDistributionSets(distributionsetTagId, assignedDSRequestBodies);
}
@Override
public ResponseEntity<Void> unassignDistributionSetUnpaged(
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
@PathVariable("distributionsetId") final Long distributionsetId) {
return unassignDistributionSet(distributionsetTagId, distributionsetId);
}
}

View File

@@ -130,14 +130,6 @@ public class MgmtTargetTagResource implements MgmtTargetTagRestApi {
return ResponseEntity.ok().build();
}
@Override
public ResponseEntity<List<MgmtTarget>> getAssignedTargets(@PathVariable("targetTagId") final Long targetTagId) {
return ResponseEntity.ok(MgmtTargetMapper.toResponse(targetManagement
.findByTag(PageRequest.of(0, MgmtRestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT), targetTagId)
.getContent()));
}
@Override
public ResponseEntity<PagedList<MgmtTarget>> getAssignedTargets(@PathVariable("targetTagId") final Long targetTagId,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
@@ -205,23 +197,4 @@ public class MgmtTargetTagResource implements MgmtTargetTagRestApi {
.collect(Collectors.toList());
}
@Override
public ResponseEntity<MgmtTargetTagAssigmentResult> toggleTagAssignmentUnpaged(
@PathVariable("targetTagId") final Long targetTagId,
@RequestBody final List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies) {
return toggleTagAssignment(targetTagId, assignedTargetRequestBodies);
}
@Override
public ResponseEntity<List<MgmtTarget>> assignTargetsUnpaged(@PathVariable("targetTagId") final Long targetTagId,
@RequestBody final List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies) {
return assignTargets(targetTagId, assignedTargetRequestBodies);
}
@Override
public ResponseEntity<Void> unassignTargetUnpaged(@PathVariable("targetTagId") final Long targetTagId,
@PathVariable("controllerId") final String controllerId) {
return unassignTarget(targetTagId, controllerId);
}
}

View File

@@ -8,13 +8,11 @@
*/
package org.eclipse.hawkbit.rest.util;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
@@ -186,96 +184,6 @@ public abstract class JsonBuilder {
}
/**
* builds a json string for the feedback for the execution "proceeding".
*
* @param id
* of the Action feedback refers to
* @return the built string
* @throws JSONException
*/
public static String deploymentActionInProgressFeedback(final String id) throws JSONException {
return deploymentActionFeedback(id, "proceeding");
}
/**
* builds a certain json string for a action feedback.
*
* @param id
* of the action the feedback refers to
* @param execution
* see ExecutionStatus
* @return the build json string
* @throws JSONException
*/
public static String deploymentActionFeedback(final String id, final String execution) throws JSONException {
return deploymentActionFeedback(id, execution, "none",
Arrays.asList(RandomStringUtils.randomAlphanumeric(1000)));
}
public static String deploymentActionFeedback(final String id, final String execution, final String message)
throws JSONException {
return deploymentActionFeedback(id, execution, "none", Arrays.asList(message));
}
public static String deploymentActionFeedback(final String id, final String execution, final String finished,
final String message) throws JSONException {
return deploymentActionFeedback(id, execution, finished, Arrays.asList(message));
}
public static String deploymentActionFeedback(final String id, final String execution, final String finished,
final Collection<String> messages) throws JSONException {
return new JSONObject().put("id", id).put("status", new JSONObject().put("execution", execution)
.put("result",
new JSONObject().put("finished", finished).put("progress",
new JSONObject().put("cnt", 2).put("of", 5)))
.put("details", new JSONArray(messages))).toString();
}
/**
* Build an invalid request body with missing result for feedback message.
*
* @param id
* id of the action
* @param execution
* the execution
* @param message
* the message
* @return a invalid request body
* @throws JSONException
*/
public static String missingResultInFeedback(final String id, final String execution, final String message)
throws JSONException {
return new JSONObject().put("id", id).put("time", "20140511T121314")
.put("status",
new JSONObject().put("execution", execution).put("details", new JSONArray().put(message)))
.toString();
}
/**
* Build an invalid request body with missing finished result for feedback
* message.
*
* @param id
* id of the action
* @param execution
* the execution
* @param message
* the message
* @return a invalid request body
* @throws JSONException
*/
public static String missingFinishedResultInFeedback(final String id, final String execution, final String message)
throws JSONException {
return new JSONObject().put("id", id).put("time", "20140511T121314")
.put("status", new JSONObject().put("execution", execution).put("result", new JSONObject())
.put("details", new JSONArray().put(message)))
.toString();
}
public static String distributionSetTypes(final List<DistributionSetType> types) throws JSONException {
final JSONArray result = new JSONArray();
@@ -512,8 +420,8 @@ public abstract class JsonBuilder {
}
});
final JSONObject json = new JSONObject().put("name", type.getName()).put("description", type.getDescription())
.put("colour", type.getColour());
final JSONObject json = new JSONObject().put("name", type.getName())
.put("description", type.getDescription()).put("colour", type.getColour());
if (dsTypes.length() != 0) {
json.put("compatibledistributionsettypes", dsTypes);
@@ -637,11 +545,6 @@ public abstract class JsonBuilder {
return json.toString();
}
public static String cancelActionFeedback(final String id, final String execution) throws JSONException {
return cancelActionFeedback(id, execution, RandomStringUtils.randomAlphanumeric(1000));
}
public static String cancelActionFeedback(final String id, final String execution, final String message)
throws JSONException {
return new JSONObject().put("id", id)

View File

@@ -36,6 +36,8 @@ final class DdiApiModelProperties {
static final String FEEDBACK_ACTION_ID = "(@deprecated) id of the action";
static final String FEEDBACK_ACTION_TIME = "timestamp of the action";
static final String CANCEL_ACTION = "action that needs to be canceled";
static final String ACTION_ID_CANCELED = "id of the action that needs to be canceled (typically identical to id field on the cancel action itself)";

View File

@@ -21,10 +21,16 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.io.ByteArrayInputStream;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback;
import org.eclipse.hawkbit.ddi.json.model.DdiProgress;
import org.eclipse.hawkbit.ddi.json.model.DdiResult;
import org.eclipse.hawkbit.ddi.json.model.DdiStatus;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
@@ -41,6 +47,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
@@ -177,11 +184,15 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
final Long actionId = getFirstAssignedActionId(assignDistributionSet(set.getId(), target.getControllerId()));
final Action cancelAction = deploymentManagement.cancelAction(actionId);
final DdiStatus ddiStatus = new DdiStatus(DdiStatus.ExecutionStatus.CLOSED,
new DdiResult(DdiResult.FinalResult.SUCCESS, new DdiProgress(2, 5)), List.of("Some feedback"));
final DdiActionFeedback feedback = new DdiActionFeedback(Instant.now().toString(), ddiStatus);
mockMvc.perform(post(
DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/" + DdiRestConstants.CANCEL_ACTION
+ "/{actionId}/feedback",
tenantAware.getCurrentTenant(), target.getControllerId(), cancelAction.getId()).content(
JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed", "Some feedback"))
objectMapper.writeValueAsString(feedback))
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
@@ -190,7 +201,10 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
parameterWithName("actionId").description(DdiApiModelProperties.ACTION_ID_CANCELED)),
requestFields(
optionalRequestFieldWithPath("id")
.description(DdiApiModelProperties.FEEDBACK_ACTION_ID),
.description(DdiApiModelProperties.FEEDBACK_ACTION_ID)
.type(JsonFieldType.NUMBER),
optionalRequestFieldWithPath("time")
.description(DdiApiModelProperties.FEEDBACK_ACTION_TIME),
requestFieldWithPath("status").description(DdiApiModelProperties.TARGET_STATUS),
requestFieldWithPath("status.execution")
.description(DdiApiModelProperties.TARGET_EXEC_STATUS).type("enum")
@@ -381,11 +395,15 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
final Long actionId = getFirstAssignedActionId(assignDistributionSet(set.getId(), target.getControllerId()));
mockMvc.perform(post(DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/"
+ DdiRestConstants.DEPLOYMENT_BASE_ACTION + "/{actionId}/feedback", tenantAware.getCurrentTenant(),
target.getControllerId(), actionId)
.content(
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed", "Feedback message"))
final DdiStatus ddiStatus = new DdiStatus(DdiStatus.ExecutionStatus.CLOSED,
new DdiResult(DdiResult.FinalResult.SUCCESS, new DdiProgress(2, 5)), List.of("Feedback message"));
final DdiActionFeedback feedback = new DdiActionFeedback(Instant.now().toString(), ddiStatus);
mockMvc.perform(post(
DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/" + DdiRestConstants.DEPLOYMENT_BASE_ACTION
+ "/{actionId}/feedback",
tenantAware.getCurrentTenant(), target.getControllerId(), actionId)
.content(objectMapper.writeValueAsString(feedback))
.contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
@@ -395,7 +413,10 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
requestFields(
optionalRequestFieldWithPath("id")
.description(DdiApiModelProperties.FEEDBACK_ACTION_ID),
.description(DdiApiModelProperties.FEEDBACK_ACTION_ID)
.type(JsonFieldType.NUMBER),
optionalRequestFieldWithPath("time")
.description(DdiApiModelProperties.FEEDBACK_ACTION_TIME),
requestFieldWithPath("status").description(DdiApiModelProperties.TARGET_STATUS),
requestFieldWithPath("status.execution")
.description(DdiApiModelProperties.TARGET_EXEC_STATUS).type("enum")