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

@@ -14,7 +14,7 @@ jobs:
working_directory: ~/hawkBit working_directory: ~/hawkBit
docker: docker:
- image: circleci/openjdk:8u181-jdk-stretch - image: circleci/openjdk:11.0.13-jdk-buster
auth: auth:
username: $DOCKERHUB_USER username: $DOCKERHUB_USER
password: $DOCKERHUB_ACCESSTOKEN password: $DOCKERHUB_ACCESSTOKEN

View File

@@ -65,7 +65,7 @@ public class BaseAmqpServiceTest {
@Description("Tests invalid null message content") @Description("Tests invalid null message content")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 0) }) @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 0) })
public void convertMessageWithNullContent() { public void convertMessageWithNullContent() {
final Message message = createMessage(null); final Message message = createMessage("".getBytes());
assertThatExceptionOfType(MessageConversionException.class) assertThatExceptionOfType(MessageConversionException.class)
.as("Expected MessageConversionException for invalid JSON") .as("Expected MessageConversionException for invalid JSON")
.isThrownBy(() -> baseAmqpService.convertMessage(message, DmfActionUpdateStatus.class)); .isThrownBy(() -> baseAmqpService.convertMessage(message, DmfActionUpdateStatus.class));

View File

@@ -32,6 +32,7 @@ public interface ArtifactEncryption {
* *
* @return secrets key/value pairs * @return secrets key/value pairs
* @throws ArtifactEncryptionFailedException * @throws ArtifactEncryptionFailedException
* thrown in case of an error while generating secrets
*/ */
Map<String, String> generateSecrets(); Map<String, String> generateSecrets();
@@ -44,6 +45,7 @@ public interface ArtifactEncryption {
* artifact stream to encrypt * artifact stream to encrypt
* @return encrypted input stream * @return encrypted input stream
* @throws ArtifactEncryptionFailedException * @throws ArtifactEncryptionFailedException
* thrown in case of an error while encrypting the provided stream
*/ */
InputStream encryptStream(final Map<String, String> secrets, final InputStream stream); InputStream encryptStream(final Map<String, String> secrets, final InputStream stream);
@@ -56,6 +58,7 @@ public interface ArtifactEncryption {
* artifact stream to decrypt * artifact stream to decrypt
* @return decrypted input stream * @return decrypted input stream
* @throws ArtifactEncryptionFailedException * @throws ArtifactEncryptionFailedException
* thrown in case of an error while decrypting the provided stream
*/ */
InputStream decryptStream(final Map<String, String> secrets, final InputStream stream); InputStream decryptStream(final Map<String, String> secrets, final InputStream stream);

View File

@@ -206,6 +206,7 @@ public interface TargetFilterQueryManagement {
* *
* @return the page with the found {@link TargetFilterQuery}s * @return the page with the found {@link TargetFilterQuery}s
* @param pageable * @param pageable
* pagination information
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
Slice<TargetFilterQuery> findWithAutoAssignDS(@NotNull Pageable pageable); Slice<TargetFilterQuery> findWithAutoAssignDS(@NotNull Pageable pageable);

View File

@@ -66,59 +66,16 @@ public interface TargetManagement {
List<Target> assignTag(@NotEmpty Collection<String> controllerIds, long tagId); List<Target> assignTag(@NotEmpty Collection<String> controllerIds, long tagId);
/** /**
* Counts number of targets with given * Counts number of targets with the given distribution set assigned.
* {@link Target#getAssignedDistributionSet()}.
*
* @param distId
* to search for
* *
* @param distId to search for
* @return number of found {@link Target}s. * @return number of found {@link Target}s.
* * @throws EntityNotFoundException if distribution set with given ID does not exist
* @throws EntityNotFoundException
* if distribution set with given ID does not exist
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
long countByAssignedDistributionSet(long distId); long countByAssignedDistributionSet(long distId);
/**
* Count {@link Target}s for all the given filter parameters.
*
* @param status
* find targets having one of these {@link TargetUpdateStatus}s.
* Set to <code>null</code> in case this is not required.
* @param overdueState
* find targets that are overdue (targets that did not respond
* during the configured intervals: poll_itvl + overdue_itvl).
* Set to <code>null</code> in case this is not required.
* @param searchText
* to find targets having the text anywhere in name or
* description. Set <code>null</code> in case this is not
* required.
* @param installedOrAssignedDistributionSetId
* to find targets having the {@link DistributionSet} as
* installed or assigned. Set to <code>null</code> in case this
* is not required.
* @param tagNames
* to find targets which are having any one in this tag names.
* Set <code>null</code> in case this is not required.
* @param selectTargetWithNoTag
* flag to select targets with no tag assigned
*
* @return the found number of {@link Target}s
*
* @throws EntityNotFoundException
* if distribution set with given ID does not exist
*
* @deprecated this method
* {@link TargetManagement#countByFilters(FilterParams)} should
* be used instead.
*/
@Deprecated
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
long countByFilters(Collection<TargetUpdateStatus> status, Boolean overdueState, String searchText,
Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, String... tagNames);
/** /**
* Count {@link Target}s for all the given filter parameters. * Count {@link Target}s for all the given filter parameters.
* *
@@ -135,14 +92,11 @@ public interface TargetManagement {
long countByFilters(@NotNull final FilterParams filterParams); long countByFilters(@NotNull final FilterParams filterParams);
/** /**
* Counts number of targets with given with given distribution set Id * Get the count of targets with the given distribution set id.
* *
* @param distId * @param distId to search for
* to search for
* @return number of found {@link Target}s. * @return number of found {@link Target}s.
* * @throws EntityNotFoundException if distribution set with given ID does not exist
* @throws EntityNotFoundException
* if distribution set with given ID does not exist
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
@@ -152,12 +106,9 @@ public interface TargetManagement {
* Checks if there is already a {@link Target} that has the given * Checks if there is already a {@link Target} that has the given
* distribution set Id assigned or installed. * distribution set Id assigned or installed.
* *
* @param distId * @param distId to search for
* to search for
* @return <code>true</code> if a {@link Target} exists. * @return <code>true</code> if a {@link Target} exists.
* * @throws EntityNotFoundException if distribution set with given ID does not exist
* @throws EntityNotFoundException
* if distribution set with given ID does not exist
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
@@ -226,8 +177,8 @@ public interface TargetManagement {
Target create(@NotNull @Valid TargetCreate create); Target create(@NotNull @Valid TargetCreate create);
/** /**
* creates multiple {@link Target}s. If some of the given {@link Target}s * creates multiple {@link Target}s. If the given {@link Target}s
* already exists in the DB a {@link EntityAlreadyExistsException} is * already exists in the DB an {@link EntityAlreadyExistsException} is
* thrown. {@link Target}s contain all objects of the parameter targets, * thrown. {@link Target}s contain all objects of the parameter targets,
* including duplicates. * including duplicates.
* *
@@ -546,25 +497,24 @@ public interface TargetManagement {
Slice<Target> findByTargetFilterQuery(@NotNull Pageable pageable, long targetFilterQueryId); Slice<Target> findByTargetFilterQuery(@NotNull Pageable pageable, long targetFilterQueryId);
/** /**
* method retrieves all {@link Target}s from the repo in the following * method retrieves all {@link Target}s from the repo in the following order:
* order:
* <p> * <p>
* 1) {@link Target}s which have the given {@link DistributionSet} as * <ol>
* {@link Target#getTarget()} {@link Target#getInstalledDistributionSet()} * <li>{@link Target}s which have the given {@link DistributionSet} as installed
* <p> * distribution set</li>
* 2) {@link Target}s which have the given {@link DistributionSet} as * <li>{@link Target}s which have the given {@link DistributionSet} as assigned
* {@link Target#getAssignedDistributionSet()} * distribution set</li>
* <p> * <li>{@link Target}s which have no connection to the given
* 3) {@link Target}s which have no connection to the given * {@link DistributionSet}</li>
* {@link DistributionSet}. * </ol>
* *
* @param pageable * @param pageable
* the page request to page the result set * the page request to page the result set
* @param orderByDistributionId * @param orderByDistributionId
* {@link DistributionSet#getId()} to be ordered by * {@link DistributionSet#getId()} to be ordered by
* @param filterParams * @param filterParams
* the filters to apply; only filters are enabled that have * the filters to apply; only filters are enabled that have non-null
* non-null value; filters are AND-gated * value; filters are AND-gated
* @return a paged result {@link Page} of the {@link Target}s in a defined * @return a paged result {@link Page} of the {@link Target}s in a defined
* order. * order.
* *
@@ -614,17 +564,16 @@ public interface TargetManagement {
Page<Target> findByRsqlAndTag(@NotNull Pageable pageable, @NotNull String rsqlParam, long tagId); Page<Target> findByRsqlAndTag(@NotNull Pageable pageable, @NotNull String rsqlParam, long tagId);
/** /**
* Toggles {@link TargetTag} assignment to given {@link Target}s by means * Toggles {@link TargetTag} assignment to given {@link Target}s by means that
* that if some (or all) of the targets in the list have the {@link Tag} not * if some (or all) of the targets in the list have the {@link Tag} not yet
* yet assigned, they will be. Only if all of theme have the tag already * assigned, they will be. Only if all of them have the tag already assigned
* assigned they will be removed instead. * they will be removed instead.
* *
* @param controllerIds * @param controllerIds
* to toggle for * to toggle for
* @param tagName * @param tagName
* to toggle * to toggle
* @return TagAssigmentResult with all meta data of the assignment outcome. * @return TagAssigmentResult with all metadata of the assignment outcome.
*
* @throws EntityNotFoundException * @throws EntityNotFoundException
* if tag with given name does not exist * if tag with given name does not exist
*/ */
@@ -641,7 +590,7 @@ public interface TargetManagement {
* to set the type to * to set the type to
* @param typeId * @param typeId
* to assign targets to * to assign targets to
* @return {@link TargetTypeAssignmentResult} with all meta data of the * @return {@link TargetTypeAssignmentResult} with all metadata of the
* assignment outcome. * assignment outcome.
* *
* @throws EntityNotFoundException * @throws EntityNotFoundException
@@ -656,7 +605,7 @@ public interface TargetManagement {
* *
* @param controllerIds * @param controllerIds
* to remove the type from * to remove the type from
* @return {@link TargetTypeAssignmentResult} with all meta data of the * @return {@link TargetTypeAssignmentResult} with all metadata of the
* assignment outcome. * assignment outcome.
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
@@ -827,13 +776,13 @@ public interface TargetManagement {
* for * for
* @param metadata * @param metadata
* the meta data entries to create or update * the meta data entries to create or update
* @return the updated or created target meta data entries * @return the updated or created target metadata entries
* *
* @throws EntityNotFoundException * @throws EntityNotFoundException
* if given target does not exist * if given target does not exist
* *
* @throws EntityAlreadyExistsException * @throws EntityAlreadyExistsException
* in case one of the meta data entry already exists for the * in case one of the metadata entry already exists for the
* specific key * specific key
* *
* @throws AssignmentQuotaExceededException * @throws AssignmentQuotaExceededException
@@ -847,7 +796,7 @@ public interface TargetManagement {
* Deletes a target meta data entry. * Deletes a target meta data entry.
* *
* @param controllerId * @param controllerId
* where meta data has to be deleted * where metadata has to be deleted
* @param key * @param key
* of the meta data element * of the meta data element
* *
@@ -863,7 +812,7 @@ public interface TargetManagement {
* @param pageable * @param pageable
* the page request to page the result * the page request to page the result
* @param controllerId * @param controllerId
* the controller id to retrieve the meta data from * the controller id to retrieve the metadata from
* *
* @return a paged result of all meta data entries for a given target id * @return a paged result of all meta data entries for a given target id
* *
@@ -888,12 +837,12 @@ public interface TargetManagement {
long countMetaDataByControllerId(@NotEmpty String controllerId); long countMetaDataByControllerId(@NotEmpty String controllerId);
/** /**
* Finds all meta data by the given target id and query. * Finds all metadata by the given target id and query.
* *
* @param pageable * @param pageable
* the page request to page the result * the page request to page the result
* @param controllerId * @param controllerId
* the controller id to retrieve the meta data from * the controller id to retrieve the metadata from
* @param rsqlParam * @param rsqlParam
* rsql query string * rsql query string
* *
@@ -932,14 +881,14 @@ public interface TargetManagement {
* Updates a target meta data value if corresponding entry exists. * Updates a target meta data value if corresponding entry exists.
* *
* @param controllerId * @param controllerId
* {@link Target} controller id of the meta data entry to be * {@link Target} controller id of the metadata entry to be
* updated * updated
* @param metadata * @param metadata
* meta data entry to be updated * meta data entry to be updated
* @return the updated meta data entry * @return the updated meta data entry
* *
* @throws EntityNotFoundException * @throws EntityNotFoundException
* in case the meta data entry does not exists and cannot be * in case the metadata entry does not exist and cannot be
* updated * updated
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)

View File

@@ -56,8 +56,10 @@ public interface TargetType extends NamedEntity {
} }
/** /**
* Unassigns a distribution set type from target types * Unassigns a {@link DistributionSetType} from {@link TargetType}
*
* @param dsTypeId * @param dsTypeId
* that will be removed from {@link TargetType}
* @return the resulting target type * @return the resulting target type
*/ */
TargetType removeDistributionSetType(final Long dsTypeId); TargetType removeDistributionSetType(final Long dsTypeId);

View File

@@ -29,6 +29,7 @@ public class TenantUsage {
* Constructor. * Constructor.
* *
* @param tenantName * @param tenantName
* name of the tenant
*/ */
public TenantUsage(final String tenantName) { public TenantUsage(final String tenantName) {
this.tenantName = tenantName; this.tenantName = tenantName;

View File

@@ -9,7 +9,7 @@
--> -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.eclipse.hawkbit</groupId> <groupId>org.eclipse.hawkbit</groupId>
@@ -21,8 +21,6 @@
<properties> <properties>
<apt.source.dir>${project.build.directory}/generated-sources/apt/</apt.source.dir> <apt.source.dir>${project.build.directory}/generated-sources/apt/</apt.source.dir>
<classgraph.version>4.8.90</classgraph.version>
<eclipselink.maven.plugin.version>2.7.5.1</eclipselink.maven.plugin.version>
</properties> </properties>
<dependencies> <dependencies>
@@ -70,6 +68,10 @@
<groupId>org.jsoup</groupId> <groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId> <artifactId>jsoup</artifactId>
</dependency> </dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<!-- Test --> <!-- Test -->
<dependency> <dependency>
@@ -96,7 +98,6 @@
<plugin> <plugin>
<groupId>com.ethlo.persistence.tools</groupId> <groupId>com.ethlo.persistence.tools</groupId>
<artifactId>eclipselink-maven-plugin</artifactId> <artifactId>eclipselink-maven-plugin</artifactId>
<version>${eclipselink.maven.plugin.version}</version>
<executions> <executions>
<execution> <execution>
<id>modelgen</id> <id>modelgen</id>
@@ -117,24 +118,10 @@
</configuration> </configuration>
<dependencies> <dependencies>
<dependency> <dependency>
<!--
Required for Java 11 since plugin version is build on
EclipseLink 2.7.5 (which doesn't have latest fixes for Java 11)
-->
<groupId>org.eclipse.persistence</groupId> <groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId> <artifactId>org.eclipse.persistence.jpa</artifactId>
<version>${eclipselink.version}</version> <version>${eclipselink.version}</version>
</dependency> </dependency>
<dependency>
<!--
Required for Java 11 since plugin uses older version (4.8.21)
which suffer from NPE while weaving. We require at least 4.8.48
see: https://github.com/ethlo/eclipselink-maven-plugin/issues/31
-->
<groupId>io.github.classgraph</groupId>
<artifactId>classgraph</artifactId>
<version>${classgraph.version}</version>
</dependency>
</dependencies> </dependencies>
</plugin> </plugin>
<plugin> <plugin>

View File

@@ -743,7 +743,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
throw new InvalidTargetAttributeException(); throw new InvalidTargetAttributeException();
} }
final JpaTarget target = (JpaTarget) targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId)) final JpaTarget target = targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)); .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
// get the modifiable attribute map // get the modifiable attribute map

View File

@@ -188,10 +188,10 @@ public class JpaTargetManagement implements TargetManagement {
final JpaTarget updatedTarget = JpaManagementHelper.touch(entityManager, targetRepository, target); final JpaTarget updatedTarget = JpaManagementHelper.touch(entityManager, targetRepository, target);
final List<TargetMetadata> createdMetadata = Collections.unmodifiableList(md.stream() final List<TargetMetadata> createdMetadata = md.stream()
.map(meta -> targetMetadataRepository .map(meta -> targetMetadataRepository
.save(new JpaTargetMetadata(meta.getKey(), meta.getValue(), updatedTarget))) .save(new JpaTargetMetadata(meta.getKey(), meta.getValue(), updatedTarget)))
.collect(Collectors.toList())); .collect(Collectors.toUnmodifiableList());
// TargetUpdatedEvent is not sent within the touch() method due to the // TargetUpdatedEvent is not sent within the touch() method due to the
// "lastModifiedAt" field being ignored in JpaTarget // "lastModifiedAt" field being ignored in JpaTarget
@@ -228,12 +228,12 @@ public class JpaTargetManagement implements TargetManagement {
// target indirectly // target indirectly
final JpaTarget target = JpaManagementHelper.touch(entityManager, targetRepository, final JpaTarget target = JpaManagementHelper.touch(entityManager, targetRepository,
getByControllerIdAndThrowIfNotFound(controllerId)); getByControllerIdAndThrowIfNotFound(controllerId));
final JpaTargetMetadata matadata = targetMetadataRepository.save(updatedMetadata); final JpaTargetMetadata metadata = targetMetadataRepository.save(updatedMetadata);
// target update event is set to ignore "lastModifiedAt" field so it is // target update event is set to ignore "lastModifiedAt" field so it is
// not send automatically within the touch() method // not send automatically within the touch() method
eventPublisherHolder.getEventPublisher() eventPublisherHolder.getEventPublisher()
.publishEvent(new TargetUpdatedEvent(target, eventPublisherHolder.getApplicationId())); .publishEvent(new TargetUpdatedEvent(target, eventPublisherHolder.getApplicationId()));
return matadata; return metadata;
} }
@Override @Override
@@ -247,7 +247,7 @@ public class JpaTargetManagement implements TargetManagement {
final JpaTarget target = JpaManagementHelper.touch(entityManager, targetRepository, final JpaTarget target = JpaManagementHelper.touch(entityManager, targetRepository,
getByControllerIdAndThrowIfNotFound(controllerId)); getByControllerIdAndThrowIfNotFound(controllerId));
targetMetadataRepository.deleteById(metadata.getId()); targetMetadataRepository.deleteById(metadata.getId());
// target update event is set to ignore "lastModifiedAt" field so it is // target update event is set to ignore "lastModifiedAt" field, so it is
// not send automatically within the touch() method // not send automatically within the touch() method
eventPublisherHolder.getEventPublisher() eventPublisherHolder.getEventPublisher()
.publishEvent(new TargetUpdatedEvent(target, eventPublisherHolder.getApplicationId())); .publishEvent(new TargetUpdatedEvent(target, eventPublisherHolder.getApplicationId()));
@@ -419,14 +419,6 @@ public class JpaTargetManagement implements TargetManagement {
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, pageable, specList); return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, pageable, specList);
} }
@Override
public long countByFilters(final Collection<TargetUpdateStatus> status, final Boolean overdueState,
final String searchText, final Long installedOrAssignedDistributionSetId,
final Boolean selectTargetWithNoTag, final String... tagNames) {
return countByFilters(new FilterParams(status, overdueState, searchText, installedOrAssignedDistributionSetId,
selectTargetWithNoTag, tagNames));
}
@Override @Override
public long countByFilters(final FilterParams filterParams) { public long countByFilters(final FilterParams filterParams) {
final List<Specification<JpaTarget>> specList = buildSpecificationList(filterParams); final List<Specification<JpaTarget>> specList = buildSpecificationList(filterParams);
@@ -590,8 +582,8 @@ public class JpaTargetManagement implements TargetManagement {
allTargets.forEach(target -> target.addTag(tag)); allTargets.forEach(target -> target.addTag(tag));
final List<Target> result = Collections final List<Target> result = allTargets.stream().map(targetRepository::save)
.unmodifiableList(allTargets.stream().map(targetRepository::save).collect(Collectors.toList())); .collect(Collectors.toUnmodifiableList());
// No reason to save the tag // No reason to save the tag
entityManager.detach(tag); entityManager.detach(tag);

View File

@@ -46,7 +46,7 @@ public class LazyControllerManagementTest extends AbstractJpaIntegrationTest {
TimeUnit.MILLISECONDS.sleep(10); TimeUnit.MILLISECONDS.sleep(10);
controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST); controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST);
TimeUnit.MILLISECONDS.sleep(repositoryProperties.getPollPersistenceFlushTime() + 1); TimeUnit.MILLISECONDS.sleep(repositoryProperties.getPollPersistenceFlushTime() + 10);
final Target updated = targetManagement.get(target.getId()).get(); final Target updated = targetManagement.get(target.getId()).get();

View File

@@ -93,7 +93,7 @@ public class SpecificationsBuilderTest {
when(criteriaBuilder.equal(any(Path.class), eq("testValue1"))).thenReturn(equalPredicate1); when(criteriaBuilder.equal(any(Path.class), eq("testValue1"))).thenReturn(equalPredicate1);
when(criteriaBuilder.equal(any(Path.class), eq("testValue2"))).thenReturn(equalPredicate2); when(criteriaBuilder.equal(any(Path.class), eq("testValue2"))).thenReturn(equalPredicate2);
when(criteriaBuilder.and(eq(equalPredicate2), eq(equalPredicate1))).thenReturn(combinedPredicate); when(criteriaBuilder.and(eq(equalPredicate1), eq(equalPredicate2))).thenReturn(combinedPredicate);
when(root.get("field1")).thenReturn(field1); when(root.get("field1")).thenReturn(field1);
when(root.get("field2")).thenReturn(field2); when(root.get("field2")).thenReturn(field2);

View File

@@ -34,6 +34,11 @@
<artifactId>hawkbit-repository-core</artifactId> <artifactId>hawkbit-repository-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-security-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.eclipse.hawkbit</groupId> <groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-artifact-repository-filesystem</artifactId> <artifactId>hawkbit-artifact-repository-filesystem</artifactId>

View File

@@ -24,10 +24,12 @@ public class CleanupTestExecutionListener extends AbstractTestExecutionListener
@Override @Override
public void afterTestMethod(final TestContext testContext) throws Exception { public void afterTestMethod(final TestContext testContext) throws Exception {
WithSpringAuthorityRule.runAsPrivileged(() -> {
final ApplicationContext applicationContext = testContext.getApplicationContext(); final ApplicationContext applicationContext = testContext.getApplicationContext();
new JpaTestRepositoryManagement(applicationContext.getBean(TenantAwareCacheManager.class), new JpaTestRepositoryManagement(applicationContext.getBean(TenantAwareCacheManager.class),
applicationContext.getBean(SystemSecurityContext.class), applicationContext.getBean(SystemSecurityContext.class),
applicationContext.getBean(SystemManagement.class)).clearTestRepository(); applicationContext.getBean(SystemManagement.class)).clearTestRepository();
return null;
});
} }
} }

View File

@@ -29,21 +29,15 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* </p> * </p>
* *
* <p> * <p>
* The answer header would look like: { "id": "51659181", "time": * The answer header would look like: { "time": "20140511T121314", "status": {
* "20140511T121314", "status": { "execution": "closed", "result": { "final": * "execution": "closed", "result": { "final": "success", "progress": {} }
* "success", "progress": {} } "details": [], } } * "details": [], } }
* </p> * </p>
* *
*/ */
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class DdiActionFeedback { 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; private final String time;
@NotNull @NotNull
@@ -51,27 +45,20 @@ public class DdiActionFeedback {
private final DdiStatus status; private final DdiStatus status;
/** /**
* Constructor. * Constructs an action-feedback
* *
* @param id
* of the actions the feedback is for
* @param time * @param time
* of the feedback * time of feedback
* @param status * @param status
* is the feedback itself * status to be appended to the action
*/ */
@JsonCreator @JsonCreator
public DdiActionFeedback(@JsonProperty("id") final Long id, @JsonProperty("time") final String time, public DdiActionFeedback(@JsonProperty(value = "time", required = true) final String time,
@JsonProperty("status") final DdiStatus status) { @JsonProperty(value = "status", required = true) final DdiStatus status) {
this.id = id;
this.time = time; this.time = time;
this.status = status; this.status = status;
} }
public Long getId() {
return id;
}
public String getTime() { public String getTime() {
return time; return time;
} }
@@ -82,7 +69,7 @@ public class DdiActionFeedback {
@Override @Override
public String toString() { 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"; 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() { private DdiRestConstants() {
// constant class, private constructor. // 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 static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import java.io.IOException; import java.io.IOException;
import java.time.Instant;
import org.assertj.core.util.Lists; import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.MismatchedInputException; import com.fasterxml.jackson.databind.exc.MismatchedInputException;
@@ -22,55 +24,39 @@ import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import io.qameta.allure.Description; import io.qameta.allure.Description;
import io.qameta.allure.Feature; import io.qameta.allure.Feature;
import io.qameta.allure.Story; 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") @Feature("Unit Tests - Direct Device Integration API")
@Story("Serializability of DDI api Models") @Story("Serialization of DDI api Models")
public class DdiActionFeedbackTest { public class DdiActionFeedbackTest {
private ObjectMapper mapper = new ObjectMapper(); private final ObjectMapper mapper = new ObjectMapper();
@Test @Test
@Description("Verify the correct serialization and deserialization of the model") @Description("Verify the correct serialization and deserialization of the model")
public void shouldSerializeAndDeserializeObject() throws IOException { public void shouldSerializeAndDeserializeObject() throws IOException {
// Setup // Setup
Long id = 123L; final String time = Instant.now().toString();
String time = "20190809T121314"; final DdiStatus ddiStatus = new DdiStatus(DdiStatus.ExecutionStatus.CLOSED, null, Lists.emptyList());
DdiStatus ddiStatus = new DdiStatus(DdiStatus.ExecutionStatus.CLOSED, null, Lists.emptyList()); final DdiActionFeedback ddiActionFeedback = new DdiActionFeedback(time, ddiStatus);
DdiActionFeedback ddiActionFeedback = new DdiActionFeedback(id, time, ddiStatus);
// Test // Test
String serializedDdiActionFeedback = mapper.writeValueAsString(ddiActionFeedback); final String serializedDdiActionFeedback = mapper.writeValueAsString(ddiActionFeedback);
DdiActionFeedback deserializedDdiActionFeedback = mapper.readValue(serializedDdiActionFeedback, final DdiActionFeedback deserializedDdiActionFeedback = mapper.readValue(serializedDdiActionFeedback,
DdiActionFeedback.class); DdiActionFeedback.class);
assertThat(serializedDdiActionFeedback).contains(id.toString(), time); assertThat(serializedDdiActionFeedback).contains(time);
assertThat(deserializedDdiActionFeedback.getId()).isEqualTo(id);
assertThat(deserializedDdiActionFeedback.getTime()).isEqualTo(time); assertThat(deserializedDdiActionFeedback.getTime()).isEqualTo(time);
assertThat(deserializedDdiActionFeedback.getStatus().toString()).isEqualTo(ddiStatus.toString()); assertThat(deserializedDdiActionFeedback.getStatus()).hasToString(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");
} }
@Test @Test
@Description("Verify that deserialization fails for known properties with a wrong datatype") @Description("Verify that deserialization fails for known properties with a wrong datatype")
public void shouldFailForObjectWithWrongDataTypes() throws IOException { public void shouldFailForObjectWithWrongDataTypes() throws IOException {
// Setup // 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( assertThatExceptionOfType(MismatchedInputException.class).isThrownBy(
() -> mapper.readValue(serializedDdiActionFeedback, DdiActionFeedback.class)); () -> mapper.readValue(serializedDdiActionFeedback, DdiActionFeedback.class));

View File

@@ -27,7 +27,7 @@ import io.qameta.allure.Story;
* Check DDI api model classes for '@JsonIgnoreProperties' annotation * Check DDI api model classes for '@JsonIgnoreProperties' annotation
*/ */
@Feature("Unit Tests - Direct Device Integration API") @Feature("Unit Tests - Direct Device Integration API")
@Story("Serializability of DDI api Models") @Story("Serialization of DDI api Models")
public class JsonIgnorePropertiesAnnotationTest { public class JsonIgnorePropertiesAnnotationTest {
@Test @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)'") "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 { public void shouldCheckAnnotationsForAllModelClasses() throws IOException {
final ClassLoader loader = Thread.currentThread().getContextClassLoader(); 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); final ImmutableSet<ClassPath.ClassInfo> topLevelClasses = ClassPath.from(loader).getTopLevelClasses(packageName);
for (ClassPath.ClassInfo classInfo : topLevelClasses) { for (final ClassPath.ClassInfo classInfo : topLevelClasses) {
Class<?> modelClass = classInfo.load(); final Class<?> modelClass = classInfo.load();
if (modelClass.getSimpleName().contains("Test") || modelClass.isEnum()) { if (modelClass.getSimpleName().contains("Test") || modelClass.isEnum()) {
continue; continue;
} }
JsonIgnoreProperties annotation = modelClass.getAnnotation(JsonIgnoreProperties.class); final JsonIgnoreProperties annotation = modelClass.getAnnotation(JsonIgnoreProperties.class);
assertThat(annotation).isNotNull(); assertThat(annotation).isNotNull();
assertThat(annotation.ignoreUnknown()).isTrue(); assertThat(annotation.ignoreUnknown()).isTrue();
} }

View File

@@ -212,7 +212,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
.orElseThrow(() -> new SoftwareModuleNotAssignedToTargetException(module, target.getControllerId())); .orElseThrow(() -> new SoftwareModuleNotAssignedToTargetException(module, target.getControllerId()));
final String range = request.getHeader("Range"); final String range = request.getHeader("Range");
String message; final String message;
if (range != null) { if (range != null) {
message = RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads range " + range + " of: " message = RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads range " + range + " of: "
+ request.getRequestURI(); + request.getRequestURI();
@@ -327,7 +327,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
if (!action.isActive()) { if (!action.isActive()) {
LOG.warn("Updating action {} with feedback {} not possible since action not active anymore.", 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); return new ResponseEntity<>(HttpStatus.GONE);
} }
@@ -346,7 +346,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
messages.addAll(feedback.getStatus().getDetails()); messages.addAll(feedback.getStatus().getDetails());
} }
Status status; final Status status;
switch (feedback.getStatus().getExecution()) { switch (feedback.getStatus().getExecution()) {
case CANCELED: case CANCELED:
LOG.debug("Controller confirmed cancel (actionId: {}, controllerId: {}) as we got {} report.", actionId, 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, private Status handleDefaultCase(final DdiActionFeedback feedback, final String controllerId, final Long actionId,
final List<String> messages) { final List<String> messages) {
Status status; final Status status;
LOG.debug("Controller reported intermediate status (actionId: {}, controllerId: {}) as we got {} report.", LOG.debug("Controller reported intermediate status (actionId: {}, controllerId: {}) as we got {} report.",
actionId, controllerId, feedback.getStatus().getExecution()); actionId, controllerId, feedback.getStatus().getExecution());
status = Status.RUNNING; status = Status.RUNNING;
@@ -401,7 +401,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
private Status handleClosedCase(final DdiActionFeedback feedback, final String controllerId, final Long actionId, private Status handleClosedCase(final DdiActionFeedback feedback, final String controllerId, final Long actionId,
final List<String> messages) { final List<String> messages) {
Status status; final Status status;
LOG.debug("Controller reported closed (actionId: {}, controllerId: {}) as we got {} report.", actionId, LOG.debug("Controller reported closed (actionId: {}, controllerId: {}) as we got {} report.", actionId,
controllerId, feedback.getStatus().getExecution()); controllerId, feedback.getStatus().getExecution());
if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) { if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) {
@@ -482,8 +482,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
} }
private DdiDeploymentBase generateDdiDeploymentBase(Target target, Action action, private DdiDeploymentBase generateDdiDeploymentBase(final Target target, final Action action,
Integer actionHistoryMessageCount) { final Integer actionHistoryMessageCount) {
final List<DdiChunk> chunks = DataConversionHelper.createChunks(target, action, artifactUrlHandler, final List<DdiChunk> chunks = DataConversionHelper.createChunks(target, action, artifactUrlHandler,
systemManagement, new ServletServerHttpRequest(requestResponseContextHolder.getHttpServletRequest()), systemManagement, new ServletServerHttpRequest(requestResponseContextHolder.getHttpServletRequest()),
controllerManagement); controllerManagement);
@@ -508,7 +508,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
final Long actionId, final EntityFactory entityFactory) { final Long actionId, final EntityFactory entityFactory) {
final List<String> messages = new ArrayList<>(); final List<String> messages = new ArrayList<>();
Status status; final Status status;
switch (feedback.getStatus().getExecution()) { switch (feedback.getStatus().getExecution()) {
case CANCELED: case CANCELED:
status = handleCaseCancelCanceled(feedback, target, actionId, messages); 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) { private static Status handleCancelClosedCase(final DdiActionFeedback feedback, final List<String> messages) {
Status status; final Status status;
if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) { if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) {
status = Status.ERROR; status = Status.ERROR;
addMessageIfEmpty("Target was not able to complete cancellation", messages); 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, private static Status handleCaseCancelCanceled(final DdiActionFeedback feedback, final Target target,
final Long actionId, final List<String> messages) { final Long actionId, final List<String> messages) {
Status status; final Status status;
LOG.error( LOG.error(
"Target reported cancel for a cancel which is not supported by the server (actionId: {}, controllerId: {}) as we got {} report.", "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()); actionId, target.getControllerId(), feedback.getStatus().getExecution());
@@ -570,7 +570,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
return verifyActionBelongsToTarget(action, target); 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())) { if (!action.getTarget().getId().equals(target.getId())) {
LOG.debug(GIVEN_ACTION_IS_NOT_ASSIGNED_TO_GIVEN_TARGET, action.getId(), target.getId()); LOG.debug(GIVEN_ACTION_IS_NOT_ASSIGNED_TO_GIVEN_TARGET, action.getId(), target.getId());
throw new EntityNotFoundException( 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.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; 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.jpa.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Artifact; 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.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser; 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.CBORFactory;
import com.fasterxml.jackson.dataformat.cbor.CBORGenerator; import com.fasterxml.jackson.dataformat.cbor.CBORGenerator;
import com.fasterxml.jackson.dataformat.cbor.CBORParser; import com.fasterxml.jackson.dataformat.cbor.CBORParser;
@@ -59,6 +69,7 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
protected static final String CANCEL_FEEDBACK = CANCEL_ACTION + "/feedback"; protected static final String CANCEL_FEEDBACK = CANCEL_ACTION + "/feedback";
protected static final int ARTIFACT_SIZE = 5 * 1024; protected static final int ARTIFACT_SIZE = 5 * 1024;
private static final ObjectMapper objectMapper = new ObjectMapper();
/** /**
* Convert JSON to a CBOR equivalent. * Convert JSON to a CBOR equivalent.
@@ -69,12 +80,12 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
* @throws IOException * @throws IOException
* Invalid JSON input * Invalid JSON input
*/ */
protected static byte[] jsonToCbor(String json) throws IOException { protected static byte[] jsonToCbor(final String json) throws IOException {
JsonFactory jsonFactory = new JsonFactory(); final JsonFactory jsonFactory = new JsonFactory();
JsonParser jsonParser = jsonFactory.createParser(json); final JsonParser jsonParser = jsonFactory.createParser(json);
ByteArrayOutputStream out = new ByteArrayOutputStream(); final ByteArrayOutputStream out = new ByteArrayOutputStream();
CBORFactory cborFactory = new CBORFactory(); final CBORFactory cborFactory = new CBORFactory();
CBORGenerator cborGenerator = cborFactory.createGenerator(out); final CBORGenerator cborGenerator = cborFactory.createGenerator(out);
while (jsonParser.nextToken() != null) { while (jsonParser.nextToken() != null) {
cborGenerator.copyCurrentEvent(jsonParser); cborGenerator.copyCurrentEvent(jsonParser);
} }
@@ -91,12 +102,12 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
* @throws IOException * @throws IOException
* Invalid CBOR input * Invalid CBOR input
*/ */
protected static String cborToJson(byte[] input) throws IOException { protected static String cborToJson(final byte[] input) throws IOException {
CBORFactory cborFactory = new CBORFactory(); final CBORFactory cborFactory = new CBORFactory();
CBORParser cborParser = cborFactory.createParser(input); final CBORParser cborParser = cborFactory.createParser(input);
JsonFactory jsonFactory = new JsonFactory(); final JsonFactory jsonFactory = new JsonFactory();
StringWriter stringWriter = new StringWriter(); final StringWriter stringWriter = new StringWriter();
JsonGenerator jsonGenerator = jsonFactory.createGenerator(stringWriter); final JsonGenerator jsonGenerator = jsonFactory.createGenerator(stringWriter);
while (cborParser.nextToken() != null) { while (cborParser.nextToken() != null) {
jsonGenerator.copyCurrentEvent(cborParser); 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, protected ResultActions postDeploymentFeedback(final String controllerId, final Long actionId, final String content,
final ResultMatcher statusMatcher) throws Exception { 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); statusMatcher);
} }
@@ -120,7 +131,7 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
protected ResultActions postCancelFeedback(final String controllerId, final Long actionId, final String content, protected ResultActions postCancelFeedback(final String controllerId, final Long actionId, final String content,
final ResultMatcher statusMatcher) throws Exception { 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); statusMatcher);
} }
@@ -164,7 +175,7 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
getDownloadAndUploadType(actionType), getDownloadAndUploadType(actionType)); 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 DistributionSet ds, final Artifact artifact, final Artifact artifactSignature, final Long actionId,
final Long osModuleId, final String downloadType, final String updateType) throws Exception { final Long osModuleId, final String downloadType, final String updateType) throws Exception {
return resultActions.andExpect(jsonPath("$.id", equalTo(String.valueOf(actionId)))) return resultActions.andExpect(jsonPath("$.id", equalTo(String.valueOf(actionId))))
@@ -234,4 +245,92 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
return "attempt"; 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 static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; 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.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory; import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.hateoas.MediaTypes; import org.springframework.hateoas.MediaTypes;
@@ -57,18 +59,22 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
final Action cancelAction = deploymentManagement.cancelAction(actionId); final Action cancelAction = deploymentManagement.cancelAction(actionId);
// check that we can get the cancel action as CBOR // check that we can get the cancel action as CBOR
final byte[] result = mvc.perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" final byte[] result = mvc
+ cancelAction.getId(), tenantAware.getCurrentTenant()).accept(DdiRestConstants.MEDIA_TYPE_CBOR)) .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()) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR)) .andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR)).andReturn().getResponse()
.andReturn().getResponse().getContentAsByteArray(); .getContentAsByteArray();
assertThat(JsonPathUtils.<String>evaluate(cborToJson(result), "$.id")).isEqualTo(String.valueOf(cancelAction.getId())); assertThat(JsonPathUtils.<String> evaluate(cborToJson(result), "$.id"))
assertThat(JsonPathUtils.<String>evaluate(cborToJson(result), "$.cancelAction.stopId")).isEqualTo(String.valueOf(actionId)); .isEqualTo(String.valueOf(cancelAction.getId()));
assertThat(JsonPathUtils.<String> evaluate(cborToJson(result), "$.cancelAction.stopId"))
.isEqualTo(String.valueOf(actionId));
// and submit feedback as CBOR // and submit feedback as CBOR
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).content( + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
jsonToCbor(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "proceeding"))) .content(jsonToCbor(getJsonProceedingCancelActionFeedback()))
.contentType(DdiRestConstants.MEDIA_TYPE_CBOR).accept(DdiRestConstants.MEDIA_TYPE_CBOR)) .contentType(DdiRestConstants.MEDIA_TYPE_CBOR).accept(DdiRestConstants.MEDIA_TYPE_CBOR))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
} }
@@ -85,11 +91,11 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
final Action cancelAction = deploymentManagement.cancelAction(actionId); final Action cancelAction = deploymentManagement.cancelAction(actionId);
// controller rejects cancelation // controller rejects cancellation
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "rejected")) .content(getJsonRejectedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
final long current = System.currentTimeMillis(); final long current = System.currentTimeMillis();
@@ -112,8 +118,9 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// and finish it // and finish it
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/"
+ actionId + "/feedback", tenantAware.getCurrentTenant()) + actionId + "/feedback", tenantAware.getCurrentTenant()).content(
.content(JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed", "success")) getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.NONE,
Collections.singletonList("message")))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
@@ -139,9 +146,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
final long timeBeforeFirstPoll = System.currentTimeMillis(); final long timeBeforeFirstPoll = System.currentTimeMillis();
mvc.perform(get("/{tenant}/controller/v1/{controller}", tenantAware.getCurrentTenant(), mvc.perform(get("/{tenant}/controller/v1/{controller}", tenantAware.getCurrentTenant(),
TestdataFactory.DEFAULT_CONTROLLER_ID).accept(MediaTypes.HAL_JSON)) TestdataFactory.DEFAULT_CONTROLLER_ID).accept(MediaTypes.HAL_JSON)).andDo(MockMvcResultPrinter.print())
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(status().isOk()).andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href", .andExpect(jsonPath("$._links.deploymentBase.href",
startsWith("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" startsWith("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/"
@@ -191,8 +197,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// controller confirmed cancelled action, should not be active anymore // controller confirmed cancelled action, should not be active anymore
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON)
.content(JsonBuilder.cancelActionFeedback(actionId.toString(), "closed")) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
activeActionsByTarget = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()) activeActionsByTarget = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
@@ -263,8 +269,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1); assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "proceeding")) .content(getJsonProceedingCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1); assertThat(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/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "resumed")) .content(getJsonResumedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1); assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(4); assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(4);
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "scheduled")) .content(getJsonScheduledCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(5); assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(5);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1); assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
@@ -290,8 +296,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1); assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "canceled")) .content(getJsonCanceledCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(6); assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(6);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1); assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
@@ -303,8 +309,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1); assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "rejected")) .content(getJsonRejectedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(7); assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(7);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1); assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
@@ -312,8 +318,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// update closed -> should remove the action from active // update closed -> should remove the action from active
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed")) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(8); assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(8);
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).isEmpty(); assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).isEmpty();
@@ -364,8 +370,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// now lets return feedback for the first cancelation // now lets return feedback for the first cancelation
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed")) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(7); assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(7);
@@ -391,8 +397,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// now lets return feedback for the second cancelation // now lets return feedback for the second cancelation
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction2.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction2.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction2.getId().toString(), "closed")) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(9); assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(9);
@@ -426,8 +432,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// now lets return feedback for the third cancelation // now lets return feedback for the third cancelation
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction3.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction3.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction3.getId().toString(), "closed")) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(13); assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(13);
@@ -447,7 +453,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
final Action cancelAction = deploymentManagement.cancelAction(actionId); 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 // assignDistributionSet creates an ActionStatus and cancel action
// stores an action status, so // stores an action status, so
// only 97 action status left // only 97 action status left
@@ -473,8 +479,8 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// not allowed methods // not allowed methods
mvc.perform(put("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(put("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed")) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
mvc.perform(delete("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(delete("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
@@ -488,36 +494,35 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest {
// bad content type // bad content type
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed")) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_ATOM_XML)
.contentType(MediaType.APPLICATION_ATOM_XML).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isUnsupportedMediaType()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isUnsupportedMediaType());
// bad body // 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/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).content(invalidFeedback)
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "546456456"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
// non existing target // non existing target
mvc.perform(post("/{tenant}/controller/v1/12345/cancelAction/" + cancelAction.getId() + "/feedback", mvc.perform(post("/{tenant}/controller/v1/12345/cancelAction/" + cancelAction.getId() + "/feedback",
tenantAware.getCurrentTenant()) tenantAware.getCurrentTenant()).content(getJsonClosedCancelActionFeedback())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
// invalid action // 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/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).content(invalidFeedback)
.content(JsonBuilder.cancelActionFeedback("sdfsdfsdfs", "closed"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
// finaly, get it right :) // finaly, get it right :)
mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/"
+ cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed")) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .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.apache.commons.lang3.RandomUtils;
import org.assertj.core.api.Condition; 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.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent; 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.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents; import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.eclipse.hawkbit.rest.exception.MessageNotReadableException; import org.eclipse.hawkbit.rest.exception.MessageNotReadableException;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
@@ -81,8 +82,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
.getContent().get(0); .getContent().get(0);
// get deployment base // get deployment base
performGet(DEPLOYMENT_BASE, performGet(DEPLOYMENT_BASE, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), status().isOk(),
MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), status().isOk(),
tenantAware.getCurrentTenant(), target.getControllerId(), action.getId().toString()); tenantAware.getCurrentTenant(), target.getControllerId(), action.getId().toString());
final Long softwareModuleId = distributionSet.getModules().stream().findAny().get().getId(); final Long softwareModuleId = distributionSet.getModules().stream().findAny().get().getId();
@@ -92,8 +92,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
status().isOk(), tenantAware.getCurrentTenant(), target.getControllerId(), status().isOk(), tenantAware.getCurrentTenant(), target.getControllerId(),
String.valueOf(softwareModuleId)); String.valueOf(softwareModuleId));
final byte[] feedback = jsonToCbor( final byte[] feedback = jsonToCbor(getJsonProceedingDeploymentActionFeedback());
JsonBuilder.deploymentActionFeedback(action.getId().toString(), "proceeding"));
postDeploymentFeedback(MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), target.getControllerId(), postDeploymentFeedback(MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), target.getControllerId(),
action.getId(), feedback, status().isOk()); action.getId(), feedback, status().isOk());
@@ -164,8 +163,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
// Run test // Run test
final long current = System.currentTimeMillis(); final long current = System.currentTimeMillis();
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID) DEFAULT_CONTROLLER_ID).andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href", .andExpect(jsonPath("$._links.deploymentBase.href",
startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString())))); startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString()))));
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery()) assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery())
@@ -262,8 +260,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final long current = System.currentTimeMillis(); final long current = System.currentTimeMillis();
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID) DEFAULT_CONTROLLER_ID).andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href", .andExpect(jsonPath("$._links.deploymentBase.href",
startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString())))); startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString()))));
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery()) 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(); final DistributionSet findDistributionSetByAction = distributionSetManagement.getByAction(action.getId()).get();
getAndVerifyDeploymentBasePayload(DEFAULT_CONTROLLER_ID, MediaType.APPLICATION_JSON, ds, getAndVerifyDeploymentBasePayload(DEFAULT_CONTROLLER_ID, MediaType.APPLICATION_JSON, ds, visibleMetadataOsKey,
visibleMetadataOsKey, visibleMetadataOsValue, artifact, artifactSignature, action.getId(), "attempt", visibleMetadataOsValue, artifact, artifactSignature, action.getId(), "attempt", "attempt",
"attempt", getOsModule(findDistributionSetByAction)); getOsModule(findDistributionSetByAction));
// Retrieved is reported // Retrieved is reported
final List<ActionStatus> actionStatusMessages = deploymentManagement final List<ActionStatus> actionStatusMessages = deploymentManagement
@@ -301,8 +298,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final Target savedTarget = createTargetAndAssertNoActiveActions(); final Target savedTarget = createTargetAndAssertNoActiveActions();
final List<Target> saved = assignDistributionSet(ds.getId(), savedTarget.getControllerId(), final List<Target> saved = assignDistributionSet(ds.getId(), savedTarget.getControllerId(),
ActionType.TIMEFORCED) ActionType.TIMEFORCED).getAssignedEntity().stream().map(Action::getTarget).collect(Collectors.toList());
.getAssignedEntity().stream().map(Action::getTarget).collect(Collectors.toList());
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1); assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()) final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
@@ -321,8 +317,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final long current = System.currentTimeMillis(); final long current = System.currentTimeMillis();
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID) DEFAULT_CONTROLLER_ID).andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href", .andExpect(jsonPath("$._links.deploymentBase.href",
startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString())))); startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString()))));
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery()) assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery())
@@ -337,9 +332,9 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
artifactSignature, action.getId(), artifactSignature, action.getId(),
findDistributionSetByAction.findFirstModuleByType(osType).get().getId(), "forced", "forced"); findDistributionSetByAction.findFirstModuleByType(osType).get().getId(), "forced", "forced");
getAndVerifyDeploymentBasePayload(DEFAULT_CONTROLLER_ID, MediaTypes.HAL_JSON, ds, artifact, getAndVerifyDeploymentBasePayload(DEFAULT_CONTROLLER_ID, MediaTypes.HAL_JSON, ds, artifact, artifactSignature,
artifactSignature, action.getId(), action.getId(), findDistributionSetByAction.findFirstModuleByType(osType).get().getId(), "forced",
findDistributionSetByAction.findFirstModuleByType(osType).get().getId(), "forced", "forced"); "forced");
// Retrieved is reported // Retrieved is reported
final Iterable<ActionStatus> actionStatusMessages = deploymentManagement final Iterable<ActionStatus> actionStatusMessages = deploymentManagement
@@ -368,8 +363,8 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final Target savedTarget = createTargetAndAssertNoActiveActions(); final Target savedTarget = createTargetAndAssertNoActiveActions();
final List<Target> saved = assignDistributionSet(ds.getId(), savedTarget.getControllerId(), final List<Target> saved = assignDistributionSet(ds.getId(), savedTarget.getControllerId(),
ActionType.DOWNLOAD_ONLY) ActionType.DOWNLOAD_ONLY).getAssignedEntity().stream().map(Action::getTarget)
.getAssignedEntity().stream().map(Action::getTarget).collect(Collectors.toList()); .collect(Collectors.toList());
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1); assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()) final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
@@ -388,8 +383,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final long current = System.currentTimeMillis(); final long current = System.currentTimeMillis();
performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
DEFAULT_CONTROLLER_ID) DEFAULT_CONTROLLER_ID).andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href", .andExpect(jsonPath("$._links.deploymentBase.href",
startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString())))); startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString()))));
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getLastTargetQuery()) 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() final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0); .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 // assign distribution set creates an action status, so only 99 left
for (int i = 0; i < 99; i++) { for (int i = 0; i < 99; i++) {
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action.getId(), feedback, status().isOk()); postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action.getId(), feedback, status().isOk());
@@ -497,10 +491,9 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
messages.add(String.valueOf(i)); 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); messages);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action.getId(), feedback, postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action.getId(), feedback, status().isForbidden());
status().isForbidden());
} }
@Test @Test
@@ -522,22 +515,22 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assertThat(targetManagement.findByUpdateStatus(PageRequest.of(0, 10), TargetUpdateStatus.UNKNOWN)).hasSize(2); assertThat(targetManagement.findByUpdateStatus(PageRequest.of(0, 10), TargetUpdateStatus.UNKNOWN)).hasSize(2);
// action1 done // action1 done
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId1, postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId1, getJsonClosedDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId1.toString(), "closed"), status().isOk()); status().isOk());
findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.PENDING, 2, Optional.of(ds1)); findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.PENDING, 2, Optional.of(ds1));
assertStatusMessagesCount(4); assertStatusMessagesCount(4);
// action2 done // action2 done
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId2, postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId2, getJsonClosedDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId2.toString(), "closed"), status().isOk()); status().isOk());
findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.PENDING, 1, Optional.of(ds2)); findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.PENDING, 1, Optional.of(ds2));
assertStatusMessagesCount(5); assertStatusMessagesCount(5);
// action3 done // action3 done
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId3, postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId3, getJsonClosedDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId3.toString(), "closed"), status().isOk()); status().isOk());
findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.IN_SYNC, 0, Optional.of(ds3)); findTargetAndAssertUpdateStatus(Optional.of(ds3), TargetUpdateStatus.IN_SYNC, 0, Optional.of(ds3));
assertStatusMessagesCount(6); assertStatusMessagesCount(6);
@@ -556,7 +549,8 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final Action action = deploymentManagement.findActionsByDistributionSet(PAGE, ds.getId()).getContent().get(0); final Action action = deploymentManagement.findActionsByDistributionSet(PAGE, ds.getId()).getContent().get(0);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action.getId(), 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()); status().isOk());
findTargetAndAssertUpdateStatus(Optional.empty(), TargetUpdateStatus.ERROR, 0, Optional.empty()); 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())); Collections.singletonList(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get()));
final Action action2 = deploymentManagement.findActiveActionsByTarget(PAGE, DEFAULT_CONTROLLER_ID).getContent() final Action action2 = deploymentManagement.findActiveActionsByTarget(PAGE, DEFAULT_CONTROLLER_ID).getContent()
.get(0); .get(0);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action2.getId(), postDeploymentFeedback(DEFAULT_CONTROLLER_ID, action2.getId(), getJsonClosedCancelActionFeedback(),
JsonBuilder.deploymentActionFeedback(action2.getId().toString(), "closed", "SUCCESS"), status().isOk()); status().isOk());
findTargetAndAssertUpdateStatus(Optional.of(ds), TargetUpdateStatus.IN_SYNC, 0, Optional.of(ds)); findTargetAndAssertUpdateStatus(Optional.of(ds), TargetUpdateStatus.IN_SYNC, 0, Optional.of(ds));
assertTargetCountByStatus(0, 0, 1); assertTargetCountByStatus(0, 0, 1);
assertThat(deploymentManagement.findInActiveActionsByTarget(PAGE, DEFAULT_CONTROLLER_ID)).hasSize(2); assertThat(deploymentManagement.findInActiveActionsByTarget(PAGE, DEFAULT_CONTROLLER_ID)).hasSize(2);
@@ -592,33 +586,33 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
// Now valid Feedback // Now valid Feedback
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonProceedingDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId.toString(), "proceeding"), status().isOk()); status().isOk());
assertActionStatusCount(i + 2, i); assertActionStatusCount(i + 2, i);
} }
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonScheduledDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId.toString(), "scheduled"), status().isOk()); status().isOk());
assertActionStatusCount(6, 5); assertActionStatusCount(6, 5);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonResumedDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId.toString(), "resumed"), status().isOk()); status().isOk());
assertActionStatusCount(7, 6); assertActionStatusCount(7, 6);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonCanceledDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId.toString(), "canceled"), status().isOk()); status().isOk());
assertStatusAndActiveActionsCount(TargetUpdateStatus.PENDING, 1); assertStatusAndActiveActionsCount(TargetUpdateStatus.PENDING, 1);
assertActionStatusCount(8, 7, 0, 0, 1); assertActionStatusCount(8, 7, 0, 0, 1);
assertTargetCountByStatus(1, 0, 0); assertTargetCountByStatus(1, 0, 0);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonRejectedDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId.toString(), "rejected"), status().isOk()); status().isOk());
assertStatusAndActiveActionsCount(TargetUpdateStatus.PENDING, 1); assertStatusAndActiveActionsCount(TargetUpdateStatus.PENDING, 1);
assertActionStatusCount(9, 6, 1, 0, 1); assertActionStatusCount(9, 6, 1, 0, 1);
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, postDeploymentFeedback(DEFAULT_CONTROLLER_ID, actionId, getJsonClosedDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed"), status().isOk()); status().isOk());
assertStatusAndActiveActionsCount(TargetUpdateStatus.IN_SYNC, 0); assertStatusAndActiveActionsCount(TargetUpdateStatus.IN_SYNC, 0);
assertActionStatusCount(10, 7, 1, 1, 1); assertActionStatusCount(10, 7, 1, 1, 1);
assertTargetCountByStatus(0, 0, 1); assertTargetCountByStatus(0, 0, 1);
@@ -635,14 +629,13 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
// target does not exist // target does not exist
postDeploymentFeedback(DEFAULT_CONTROLLER_ID, 1234L, postDeploymentFeedback(DEFAULT_CONTROLLER_ID, 1234L, getJsonProceedingDeploymentActionFeedback(),
JsonBuilder.deploymentActionInProgressFeedback("1234"), status().isNotFound()); status().isNotFound());
final Target savedTarget = testdataFactory.createTarget(DEFAULT_CONTROLLER_ID); final Target savedTarget = testdataFactory.createTarget(DEFAULT_CONTROLLER_ID);
// Action does not exist // Action does not exist
postDeploymentFeedback("4713", 1234L, JsonBuilder.deploymentActionInProgressFeedback("1234"), postDeploymentFeedback("4713", 1234L, getJsonProceedingDeploymentActionFeedback(), status().isNotFound());
status().isNotFound());
assignDistributionSet(savedSet, Collections.singletonList(savedTarget)).getAssignedEntity().iterator().next(); assignDistributionSet(savedSet, Collections.singletonList(savedTarget)).getAssignedEntity().iterator().next();
assignDistributionSet(savedSet2, Collections.singletonList(testdataFactory.createTarget("4713"))); assignDistributionSet(savedSet2, Collections.singletonList(testdataFactory.createTarget("4713")));
@@ -651,8 +644,8 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
.getContent().get(0); .getContent().get(0);
// action exists but is not assigned to this target // action exists but is not assigned to this target
postDeploymentFeedback("4713", updateAction.getId(), postDeploymentFeedback("4713", updateAction.getId(), getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING,
JsonBuilder.deploymentActionInProgressFeedback(updateAction.getId().toString()), status().isNotFound()); DdiResult.FinalResult.NONE, Collections.singletonList("")), status().isNotFound());
// not allowed methods // not allowed methods
mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(), mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(),
@@ -669,11 +662,11 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
@Test @Test
@Description("Ensures that an invalid id in feedback body returns a bad request.") @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 = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3), @Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @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 { public void invalidIdInFeedbackReturnsBadRequest() throws Exception {
final Target target = testdataFactory.createTarget("1080"); final Target target = testdataFactory.createTarget("1080");
final DistributionSet ds = testdataFactory.createDistributionSet(""); final DistributionSet ds = testdataFactory.createDistributionSet("");
@@ -681,17 +674,17 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds.getId(), "1080"); assignDistributionSet(ds.getId(), "1080");
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent() final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0); .get(0);
postDeploymentFeedback("1080", action.getId(), final String invalidFeedback = "{\"id\":\"AAAA\",\"status\":{\"execution\":\"proceeding\",\"result\":{\"finished\":\"none\",\"progress\":{\"cnt\":2,\"of\":5}},\"details\":\"details\"]}}";
JsonBuilder.deploymentActionInProgressFeedback("AAAA"), status().isBadRequest()); postDeploymentFeedback("1080", action.getId(), invalidFeedback, status().isBadRequest());
} }
@Test @Test
@Description("Ensures that a missing feedback result in feedback body returns a bad request.") @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 = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3), @Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @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 { public void missingResultAttributeInFeedbackReturnsBadRequest() throws Exception {
final Target target = testdataFactory.createTarget("1080"); final Target target = testdataFactory.createTarget("1080");
@@ -700,20 +693,21 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds.getId(), "1080"); assignDistributionSet(ds.getId(), "1080");
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent() final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0); .get(0);
final String missingResultInFeedback = JsonBuilder.missingResultInFeedback(action.getId().toString(), "closed",
"test"); final String missingResultInFeedback = getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, (DdiResult) null,
postDeploymentFeedback("1080", action.getId(), missingResultInFeedback, Collections.singletonList("test"));
status().isBadRequest()).andExpect(jsonPath("$.*", hasSize(3))).andExpect( postDeploymentFeedback("1080", action.getId(), missingResultInFeedback, status().isBadRequest())
jsonPath("$.exceptionClass", equalTo(MessageNotReadableException.class.getCanonicalName()))); .andExpect(jsonPath("$.*", hasSize(3)))
.andExpect(jsonPath("$.exceptionClass", equalTo(MessageNotReadableException.class.getCanonicalName())));
} }
@Test @Test
@Description("Ensures that a missing finished result in feedback body returns a bad request.") @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 = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3), @Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @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 { public void missingFinishedAttributeInFeedbackReturnsBadRequest() throws Exception {
final Target target = testdataFactory.createTarget("1080"); final Target target = testdataFactory.createTarget("1080");
@@ -722,11 +716,13 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent() final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()
.get(0); .get(0);
final String missingFinishedResultInFeedback = JsonBuilder final String missingFinishedResultInFeedback = getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED,
.missingFinishedResultInFeedback(action.getId().toString(), "closed", "test"); new DdiResult(null, null),
postDeploymentFeedback("1080", action.getId(), missingFinishedResultInFeedback, Collections.singletonList("test"));
status().isBadRequest()).andExpect(jsonPath("$.*", hasSize(3))).andExpect(
jsonPath("$.exceptionClass", equalTo(MessageNotReadableException.class.getCanonicalName()))); 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) { 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 java.util.stream.Stream;
import org.apache.commons.lang3.RandomUtils; 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.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent; 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.model.Target;
import org.eclipse.hawkbit.repository.test.matcher.Expect; import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents; import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
@@ -77,8 +78,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Target target = testdataFactory.createTarget(); final Target target = testdataFactory.createTarget();
final DistributionSet ds = testdataFactory.createDistributionSet(""); final DistributionSet ds = testdataFactory.createDistributionSet("");
final Long actionId = getFirstAssignedActionId(assignDistributionSet(ds, target)); final Long actionId = getFirstAssignedActionId(assignDistributionSet(ds, target));
postDeploymentFeedback(target.getControllerId(), actionId, postDeploymentFeedback(target.getControllerId(), actionId, getJsonClosedDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed"), status().isOk()); status().isOk());
// get installed base // get installed base
performGet(INSTALLED_BASE, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), status().isOk(), 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); actionId1, ds1.findFirstModuleByType(osType).get().getId(), Action.ActionType.SOFT);
postDeploymentFeedback(target.getControllerId(), actionId1, postDeploymentFeedback(target.getControllerId(), actionId1,
JsonBuilder.deploymentActionFeedback(actionId1.toString(), "closed", "success", "Closed"), getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Closed")),
status().isOk()); status().isOk());
getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds1, artifact1, artifactSignature1, 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); actionId2, ds2.findFirstModuleByType(osType).get().getId(), Action.ActionType.FORCED);
postDeploymentFeedback(target.getControllerId(), actionId2, postDeploymentFeedback(target.getControllerId(), actionId2,
JsonBuilder.deploymentActionFeedback(actionId2.toString(), "closed", "success", "Closed"), getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Closed")),
status().isOk()); status().isOk());
getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds2, artifact2, artifactSignature2, getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds2, artifact2, artifactSignature2,
@@ -155,7 +158,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
startsWith(installedBaseLink(CONTROLLER_ID, actionId2.toString())))) startsWith(installedBaseLink(CONTROLLER_ID, actionId2.toString()))))
.andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist()); .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, getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds1, artifact1, artifactSignature1,
actionId1, ds1.findFirstModuleByType(osType).get().getId(), Action.ActionType.SOFT); 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)); assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
deploymentManagement.cancelAction(actionId1); deploymentManagement.cancelAction(actionId1);
postCancelFeedback(target.getControllerId(), 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 // assign ds1, action2 - and provide cancel feedback
final Long actionId2 = getFirstAssignedActionId( final Long actionId2 = getFirstAssignedActionId(
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.FORCED)); assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.FORCED));
deploymentManagement.cancelAction(actionId2); deploymentManagement.cancelAction(actionId2);
postCancelFeedback(target.getControllerId(), 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 // assign ds1, action 3 - and provide success feedback
final Long actionId3 = getFirstAssignedActionId( final Long actionId3 = getFirstAssignedActionId(
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT)); assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
postDeploymentFeedback(target.getControllerId(), actionId3, postDeploymentFeedback(target.getControllerId(), actionId3,
JsonBuilder.deploymentActionFeedback(actionId3.toString(), "closed", "success", "Closed"), getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Canceled")),
status().isOk()); status().isOk());
// Test: latest succeeded action is returned in installedBase // Test: latest succeeded action is returned in installedBase
@@ -228,7 +237,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Long actionId1 = getFirstAssignedActionId( final Long actionId1 = getFirstAssignedActionId(
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT)); assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
postDeploymentFeedback(target.getControllerId(), actionId1, postDeploymentFeedback(target.getControllerId(), actionId1,
JsonBuilder.deploymentActionFeedback(actionId1.toString(), "closed", "success", "Success"), getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Success")),
status().isOk()); status().isOk());
// assign ds2, action2 - assign ds1, action 3 - and cancel both // 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)); assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
deploymentManagement.cancelAction(actionId2); deploymentManagement.cancelAction(actionId2);
postCancelFeedback(target.getControllerId(), 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); deploymentManagement.cancelAction(actionId3);
postCancelFeedback(target.getControllerId(), 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 // Test: the succeeded action is returned in installedBase instead of the latest
// cancelled action // cancelled action
@@ -279,7 +293,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Long actionId1 = getFirstAssignedActionId( final Long actionId1 = getFirstAssignedActionId(
assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT)); assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
postDeploymentFeedback(target.getControllerId(), actionId1, postDeploymentFeedback(target.getControllerId(), actionId1,
JsonBuilder.deploymentActionFeedback(actionId1.toString(), "closed", "success", "Success"), getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Success")),
status().isOk()); status().isOk());
// assign ds2, action2 - assign ds1, action 3 - and cancel action 2 // 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)); assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT));
deploymentManagement.cancelAction(actionId2); deploymentManagement.cancelAction(actionId2);
postCancelFeedback(target.getControllerId(), 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 // Test: the succeeded action is returned in installedBase instead of the latest
// cancelled action // cancelled action
@@ -338,8 +355,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final DistributionSet ds = testdataFactory.createDistributionSet(""); final DistributionSet ds = testdataFactory.createDistributionSet("");
final Long actionId = getFirstAssignedActionId(assignDistributionSet(ds, target)); final Long actionId = getFirstAssignedActionId(assignDistributionSet(ds, target));
postDeploymentFeedback(target.getControllerId(), actionId, postDeploymentFeedback(target.getControllerId(), actionId, getJsonClosedDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed"), status().isOk()); status().isOk());
final Long softwareModuleId = ds.getModules().stream().findAny().get().getId(); final Long softwareModuleId = ds.getModules().stream().findAny().get().getId();
performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isOk(), performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isOk(),
@@ -385,7 +402,8 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
assignDistributionSet(ds.getId(), target.getControllerId(), actionType)); assignDistributionSet(ds.getId(), target.getControllerId(), actionType));
postDeploymentFeedback(target.getControllerId(), actionId, postDeploymentFeedback(target.getControllerId(), actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed", "success", "Closed"), getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Closed")),
status().isOk()); status().isOk());
// Run test // Run test
@@ -433,10 +451,10 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
.andExpect(jsonPath("$._links.deploymentBase.href").exists()) .andExpect(jsonPath("$._links.deploymentBase.href").exists())
.andExpect(jsonPath("$._links.installedBase.href").doesNotExist()); .andExpect(jsonPath("$._links.installedBase.href").doesNotExist());
postDeploymentFeedback(target.getControllerId(), actionId, postDeploymentFeedback(target.getControllerId(), actionId, getJsonDownloadDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId.toString(), "download"), status().isOk()); status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId, postDeploymentFeedback(target.getControllerId(), actionId, getJsonDownloadedDeploymentActionFeedback(),
JsonBuilder.deploymentActionFeedback(actionId.toString(), "downloaded"), status().isOk()); status().isOk());
// Test // Test
performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(), performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(),
@@ -448,7 +466,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
@ParameterizedTest @ParameterizedTest
@MethodSource("org.eclipse.hawkbit.ddi.rest.resource.DdiInstalledBaseTest#actionTypeForDeployment") @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.") @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 // Prepare test data
final Target target = testdataFactory.createTarget(); final Target target = testdataFactory.createTarget();
final DistributionSet ds = testdataFactory.createDistributionSet(""); final DistributionSet ds = testdataFactory.createDistributionSet("");
@@ -461,9 +479,11 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
.andExpect(jsonPath("$._links.installedBase.href").doesNotExist()); .andExpect(jsonPath("$._links.installedBase.href").doesNotExist());
postDeploymentFeedback(target.getControllerId(), actionId, postDeploymentFeedback(target.getControllerId(), actionId,
JsonBuilder.deploymentActionFeedback(actionId.toString(), "proceeding"), status().isOk()); getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE),
status().isOk());
postDeploymentFeedback(target.getControllerId(), actionId, 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()); status().isOk());
// Test // Test
@@ -482,14 +502,20 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()) final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0); .getContent().get(0);
postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(), JsonBuilder.deploymentActionFeedback( postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(),
savedAction.getId().toString(), "scheduled", "Installation scheduled"), status().isOk()); getJsonActionFeedback(DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.NONE,
Collections.singletonList("Installation scheduled")),
status().isOk());
postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(), JsonBuilder.deploymentActionFeedback( postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(),
savedAction.getId().toString(), "proceeding", "Installation proceeding"), status().isOk()); getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE,
Collections.singletonList("Installation proceeding")),
status().isOk());
// only this feedback triggers the ActionUpdateEvent // only this feedback triggers the ActionUpdateEvent
postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(), JsonBuilder.deploymentActionFeedback( postDeploymentFeedback(savedTarget.getControllerId(), savedAction.getId(),
savedAction.getId().toString(), "closed", "success", "Installation completed"), status().isOk()); getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS,
Collections.singletonList("Installation completed")),
status().isOk());
// Test // Test
// for zero input no action history is returned // for zero input no action history is returned
@@ -545,8 +571,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
final DistributionSet savedSet = testdataFactory.createDistributionSet(""); final DistributionSet savedSet = testdataFactory.createDistributionSet("");
final Long actionId = getFirstAssignedActionId(assignDistributionSet(savedSet, toAssign)); final Long actionId = getFirstAssignedActionId(assignDistributionSet(savedSet, toAssign));
postDeploymentFeedback(CONTROLLER_ID, actionId, postDeploymentFeedback(CONTROLLER_ID, actionId, getJsonClosedCancelActionFeedback(), status().isOk());
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed", "success"), status().isOk());
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, actionId)) mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, actionId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, actionId) 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 java.util.UUID;
import org.apache.commons.lang3.RandomStringUtils; 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.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
@@ -88,9 +90,9 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Test @Test
@Description("Ensure that the root poll resource is available as CBOR") @Description("Ensure that the root poll resource is available as CBOR")
void rootPollResourceCbor() throws Exception { void rootPollResourceCbor() throws Exception {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711) mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711).accept(DdiRestConstants.MEDIA_TYPE_CBOR))
.accept(DdiRestConstants.MEDIA_TYPE_CBOR)).andDo(MockMvcResultPrinter.print()) .andDo(MockMvcResultPrinter.print()).andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR))
.andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR)).andExpect(status().isOk()); .andExpect(status().isOk());
} }
@Test @Test
@@ -147,11 +149,12 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
// make a poll, audit information should not be changed, run as // make a poll, audit information should not be changed, run as
// controller principal! // controller principal!
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS),
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownTargetControllerId)) () -> {
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownTargetControllerId))
return null; .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
}); return null;
});
// verify that audit information has not changed // verify that audit information has not changed
final Target targetVerify = targetManagement.getByControllerID(knownTargetControllerId).get(); final Target targetVerify = targetManagement.getByControllerID(knownTargetControllerId).get();
@@ -175,7 +178,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
void rootRsPlugAndPlay() throws Exception { void rootRsPlugAndPlay() throws Exception {
final long current = System.currentTimeMillis(); final long current = System.currentTimeMillis();
String controllerId = "4711"; final String controllerId = "4711";
mvc.perform(get(CONTROLLER_BASE, "default-tenant", controllerId)).andDo(MockMvcResultPrinter.print()) mvc.perform(get(CONTROLLER_BASE, "default-tenant", controllerId)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaTypes.HAL_JSON)) .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 = TargetPollEvent.class, count = 1),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) }) @Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void pollWithModifiedGlobalPollingTime() throws Exception { void pollWithModifiedGlobalPollingTime() throws Exception {
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withUser("tenantadmin", HAS_AUTH_TENANT_CONFIGURATION), () -> { WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withUser("tenantadmin", HAS_AUTH_TENANT_CONFIGURATION),
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL, () -> {
"00:02:00"); tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
return null; "00:02:00");
}); return null;
});
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withUser("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withUser("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711)) mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711)).andDo(MockMvcResultPrinter.print())
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(status().isOk()).andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:02:00"))); .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:02:00")));
return null; return null;
}); });
@@ -230,7 +233,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@Expect(type = TargetAttributesRequestedEvent.class, count = 1), @Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6) }) @Expect(type = SoftwareModuleCreatedEvent.class, count = 6) })
void rootRsNotModified() throws Exception { void rootRsNotModified() throws Exception {
String controllerId = "4711"; final String controllerId = "4711";
final String etag = mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId)) final String etag = mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON)) .andExpect(content().contentType(MediaTypes.HAL_JSON))
@@ -308,7 +311,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) }) @Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
void rootRsPrecommissioned() throws Exception { void rootRsPrecommissioned() throws Exception {
String controllerId = "4711"; final String controllerId = "4711";
testdataFactory.createTarget(controllerId); testdataFactory.createTarget(controllerId);
assertThat(targetManagement.getByControllerID(controllerId).get().getUpdateStatus()) assertThat(targetManagement.getByControllerID(controllerId).get().getUpdateStatus())
@@ -339,12 +342,12 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
final long create = System.currentTimeMillis(); final long create = System.currentTimeMillis();
// make a poll, audit information should be set on plug and play // make a poll, audit information should be set on plug and play
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS),
mvc.perform( () -> {
get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownControllerId1)) mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownControllerId1))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
return null; return null;
}); });
// verify // verify
final Target target = targetManagement.getByControllerID(knownControllerId1).get(); final Target target = targetManagement.getByControllerID(knownControllerId1).get();
@@ -414,9 +417,8 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
final Map<String, String> attributes = Collections.singletonMap("AttributeKey", "AttributeValue"); final Map<String, String> attributes = Collections.singletonMap("AttributeKey", "AttributeValue");
assertThatAttributesUpdateIsRequested(savedTarget.getControllerId()); assertThatAttributesUpdateIsRequested(savedTarget.getControllerId());
mvc.perform(put(CONTROLLER_BASE + "/configData", tenantAware.getCurrentTenant(), mvc.perform(put(CONTROLLER_BASE + "/configData", tenantAware.getCurrentTenant(), savedTarget.getControllerId())
savedTarget.getControllerId()).content(JsonBuilder.configData(attributes).toString()) .content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()); .andExpect(status().isOk());
assertThatAttributesUpdateIsNotRequested(savedTarget.getControllerId()); assertThatAttributesUpdateIsNotRequested(savedTarget.getControllerId());
@@ -465,8 +467,9 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
if (message == null) { if (message == null) {
message = RandomStringUtils.randomAlphanumeric(1000); 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( return mvc.perform(
post(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(), target.getControllerId(), action.getId()) post(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(), target.getControllerId(), action.getId())
.content(feedback).contentType(MediaType.APPLICATION_JSON)); .content(feedback).contentType(MediaType.APPLICATION_JSON));
@@ -503,8 +506,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=2", tenantAware.getCurrentTenant(), 911, savedAction.getId()) mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=2", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages", .andExpect(jsonPath("$.actionHistory.messages",
hasItem(containsString(TARGET_COMPLETED_INSTALLATION_MSG)))) hasItem(containsString(TARGET_COMPLETED_INSTALLATION_MSG))))
@@ -540,8 +542,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=0", tenantAware.getCurrentTenant(), 911, savedAction.getId()) mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=0", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages").doesNotExist()); .andExpect(jsonPath("$.actionHistory.messages").doesNotExist());
@@ -577,8 +578,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=-1", tenantAware.getCurrentTenant(), 911, savedAction.getId()) mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=-1", tenantAware.getCurrentTenant(), 911, savedAction.getId())
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.actionHistory.messages", .andExpect(jsonPath("$.actionHistory.messages",
hasItem(containsString(TARGET_SCHEDULED_INSTALLATION_MSG)))) hasItem(containsString(TARGET_SCHEDULED_INSTALLATION_MSG))))
@@ -593,13 +593,14 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
void sleepTimeResponseForDifferentMaintenanceWindowParameters() throws Exception { void sleepTimeResponseForDifferentMaintenanceWindowParameters() throws Exception {
final DistributionSet ds = testdataFactory.createDistributionSet(""); final DistributionSet ds = testdataFactory.createDistributionSet("");
WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withUser("tenantadmin", HAS_AUTH_TENANT_CONFIGURATION), () -> { WithSpringAuthorityRule.runAs(WithSpringAuthorityRule.withUser("tenantadmin", HAS_AUTH_TENANT_CONFIGURATION),
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL, () -> {
"00:05:00"); tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.MIN_POLLING_TIME_INTERVAL, "00:05:00");
"00:01:00"); tenantConfigurationManagement
return null; .addOrUpdateConfiguration(TenantConfigurationKey.MIN_POLLING_TIME_INTERVAL, "00:01:00");
}); return null;
});
final Target savedTarget = testdataFactory.createTarget("1911"); final Target savedTarget = testdataFactory.createTarget("1911");
assignDistributionSetWithMaintenanceWindow(ds.getId(), savedTarget.getControllerId(), getTestSchedule(16), assignDistributionSetWithMaintenanceWindow(ds.getId(), savedTarget.getControllerId(), getTestSchedule(16),
@@ -648,9 +649,9 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()) final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0); .getContent().get(0);
mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "1911", mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "1911", action.getId())
action.getId()).accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(status().isOk()).andExpect(jsonPath("$.deployment.download", equalTo("forced"))) .andExpect(jsonPath("$.deployment.download", equalTo("forced")))
.andExpect(jsonPath("$.deployment.update", equalTo("skip"))) .andExpect(jsonPath("$.deployment.update", equalTo("skip")))
.andExpect(jsonPath("$.deployment.maintenanceWindow", equalTo("unavailable"))); .andExpect(jsonPath("$.deployment.maintenanceWindow", equalTo("unavailable")));
} }
@@ -668,9 +669,9 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()) final Action action = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())
.getContent().get(0); .getContent().get(0);
mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "1911", mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "1911", action.getId())
action.getId()).accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(status().isOk()).andExpect(jsonPath("$.deployment.download", equalTo("forced"))) .andExpect(jsonPath("$.deployment.download", equalTo("forced")))
.andExpect(jsonPath("$.deployment.update", equalTo("forced"))) .andExpect(jsonPath("$.deployment.update", equalTo("forced")))
.andExpect(jsonPath("$.deployment.maintenanceWindow", equalTo("available"))); .andExpect(jsonPath("$.deployment.maintenanceWindow", equalTo("available")));
} }
@@ -704,8 +705,9 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
throws Exception { throws Exception {
final String expectedDeploymentBaseLink = String.format("/%s/controller/v1/%s/deploymentBase/%d", final String expectedDeploymentBaseLink = String.format("/%s/controller/v1/%s/deploymentBase/%d",
tenantAware.getCurrentTenant(), controllerId, expectedActionId); tenantAware.getCurrentTenant(), controllerId, expectedActionId);
mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId) mvc.perform(
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$._links.deploymentBase.href", containsString(expectedDeploymentBaseLink))); .andExpect(jsonPath("$._links.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.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.security.DosFilter; import org.eclipse.hawkbit.security.DosFilter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@@ -114,7 +113,7 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest {
@Description("Ensures that a WRITE DoS attempt is blocked ") @Description("Ensures that a WRITE DoS attempt is blocked ")
void putPostFloddingAttackThatisPrevented() throws Exception { void putPostFloddingAttackThatisPrevented() throws Exception {
final Long actionId = prepareDeploymentBase(); final Long actionId = prepareDeploymentBase();
final String feedback = JsonBuilder.deploymentActionFeedback(actionId.toString(), "proceeding"); final String feedback = getJsonProceedingDeploymentActionFeedback();
MvcResult result = null; MvcResult result = null;
int requests = 0; 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 @SuppressWarnings("squid:S2925") // No idea how to get rid of the Thread.sleep here
void acceptablePutPostLoad() throws Exception { void acceptablePutPostLoad() throws Exception {
final Long actionId = prepareDeploymentBase(); final Long actionId = prepareDeploymentBase();
final String feedback = JsonBuilder.deploymentActionFeedback(actionId.toString(), "proceeding"); final String feedback = getJsonProceedingDeploymentActionFeedback();
for (int x = 0; x < 5; x++) { for (int x = 0; x < 5; x++) {
// sleep for one second // sleep for one second

View File

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

View File

@@ -73,14 +73,14 @@ public interface MgmtDistributionSetTagRestApi {
ResponseEntity<MgmtTag> getDistributionSetTag(@PathVariable("distributionsetTagId") Long distributionsetTagId); ResponseEntity<MgmtTag> getDistributionSetTag(@PathVariable("distributionsetTagId") Long distributionsetTagId);
/** /**
* Handles the POST request of creating new distribution set tag. The * Handles the POST request of creating new distribution set tag. The request
* request body must always be a list of tags. * body must always be a list of tags.
* *
* @param tags * @param tags
* the distribution set tags to be created. * the distribution set tags to be created.
* @return In case all modules could successful created the ResponseEntity * @return In case all modules could successful created the ResponseEntity with
* with status code 201 - Created. The Response Body are the created * status code 201 - Created. The Response Body contains the created
* distribution set tags but without ResponseBody. * distribution set tags but without details.
*/ */
@PostMapping(consumes = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = { @PostMapping(consumes = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }) MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
@@ -93,9 +93,9 @@ public interface MgmtDistributionSetTagRestApi {
* @param distributionsetTagId * @param distributionsetTagId
* the ID of the distribution set tag * the ID of the distribution set tag
* @param restDSTagRest * @param restDSTagRest
* the the request body to be updated * the request body to be updated
* @return status OK if update is successful and the updated distribution * @return status OK if update is successful and the updated distribution set
* set tag. * tag.
*/ */
@PutMapping(value = "/{distributionsetTagId}", consumes = { MediaTypes.HAL_JSON_VALUE, @PutMapping(value = "/{distributionsetTagId}", consumes = { MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE }, produces = { 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_SORTING, required = false) String sortParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) String rsqlParam); @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 * Handles the POST request to toggle the assignment of distribution sets by
* the given tag id. * the given tag id.
@@ -182,28 +162,6 @@ public interface MgmtDistributionSetTagRestApi {
@PathVariable("distributionsetTagId") Long distributionsetTagId, @PathVariable("distributionsetTagId") Long distributionsetTagId,
List<MgmtAssignedDistributionSetRequestBody> assignedDSRequestBodies); 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. * Handles the POST request to assign distribution sets to the given tag id.
* *
@@ -221,27 +179,6 @@ public interface MgmtDistributionSetTagRestApi {
@PathVariable("distributionsetTagId") Long distributionsetTagId, @PathVariable("distributionsetTagId") Long distributionsetTagId,
List<MgmtAssignedDistributionSetRequestBody> assignedDSRequestBodies); 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 * Handles the DELETE request to unassign one distribution set from the
* given tag id. * given tag id.
@@ -257,22 +194,4 @@ public interface MgmtDistributionSetTagRestApi {
ResponseEntity<Void> unassignDistributionSet(@PathVariable("distributionsetTagId") Long distributionsetTagId, ResponseEntity<Void> unassignDistributionSet(@PathVariable("distributionsetTagId") Long distributionsetTagId,
@PathVariable("distributionsetId") Long distributionsetId); @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"; 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. * 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"; 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. * The tag URL mapping rest resource.
*/ */

View File

@@ -112,25 +112,6 @@ public interface MgmtTargetTagRestApi {
@DeleteMapping(value = "/{targetTagId}") @DeleteMapping(value = "/{targetTagId}")
ResponseEntity<Void> deleteTargetTag(@PathVariable("targetTagId") Long 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 * Handles the GET request of retrieving all assigned targets by the given
* tag id. * tag id.
@@ -177,27 +158,6 @@ public interface MgmtTargetTagRestApi {
ResponseEntity<MgmtTargetTagAssigmentResult> toggleTagAssignment(@PathVariable("targetTagId") Long targetTagId, ResponseEntity<MgmtTargetTagAssigmentResult> toggleTagAssignment(@PathVariable("targetTagId") Long targetTagId,
List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies); 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. * 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, ResponseEntity<List<MgmtTarget>> assignTargets(@PathVariable("targetTagId") Long targetTagId,
List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies); 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. * 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}") @DeleteMapping(value = MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING + "/{controllerId}")
ResponseEntity<Void> unassignTarget(@PathVariable("targetTagId") Long targetTagId, ResponseEntity<Void> unassignTarget(@PathVariable("targetTagId") Long targetTagId,
@PathVariable("controllerId") String controllerId); @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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
@@ -139,15 +138,6 @@ public class MgmtDistributionSetTagResource implements MgmtDistributionSetTagRes
return ResponseEntity.ok().build(); 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 @Override
public ResponseEntity<PagedList<MgmtDistributionSet>> getAssignedDistributionSets( public ResponseEntity<PagedList<MgmtDistributionSet>> getAssignedDistributionSets(
@PathVariable("distributionsetTagId") final Long distributionsetTagId, @PathVariable("distributionsetTagId") final Long distributionsetTagId,
@@ -204,7 +194,7 @@ public class MgmtDistributionSetTagResource implements MgmtDistributionSetTagRes
LOG.debug("Assign DistributionSet {} for ds tag {}", assignedDSRequestBodies.size(), distributionsetTagId); LOG.debug("Assign DistributionSet {} for ds tag {}", assignedDSRequestBodies.size(), distributionsetTagId);
final List<DistributionSet> assignedDs = this.distributionSetManagement final List<DistributionSet> assignedDs = this.distributionSetManagement
.assignTag(findDistributionSetIds(assignedDSRequestBodies), distributionsetTagId); .assignTag(findDistributionSetIds(assignedDSRequestBodies), distributionsetTagId);
LOG.debug("Assignd DistributionSet {}", assignedDs.size()); LOG.debug("Assigned DistributionSet {}", assignedDs.size());
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDistributionSets(assignedDs)); return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDistributionSets(assignedDs));
} }
@@ -227,26 +217,4 @@ public class MgmtDistributionSetTagResource implements MgmtDistributionSetTagRes
return assignedDistributionSetRequestBodies.stream() return assignedDistributionSetRequestBodies.stream()
.map(MgmtAssignedDistributionSetRequestBody::getDistributionSetId).collect(Collectors.toList()); .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(); 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 @Override
public ResponseEntity<PagedList<MgmtTarget>> getAssignedTargets(@PathVariable("targetTagId") final Long targetTagId, 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, @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()); .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; package org.eclipse.hawkbit.rest.util;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.RolloutGroup; 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 { public static String distributionSetTypes(final List<DistributionSetType> types) throws JSONException {
final JSONArray result = new JSONArray(); 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()) final JSONObject json = new JSONObject().put("name", type.getName())
.put("colour", type.getColour()); .put("description", type.getDescription()).put("colour", type.getColour());
if (dsTypes.length() != 0) { if (dsTypes.length() != 0) {
json.put("compatibledistributionsettypes", dsTypes); json.put("compatibledistributionsettypes", dsTypes);
@@ -637,11 +545,6 @@ public abstract class JsonBuilder {
return json.toString(); 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) public static String cancelActionFeedback(final String id, final String execution, final String message)
throws JSONException { throws JSONException {
return new JSONObject().put("id", id) 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_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 CANCEL_ACTION = "action that needs to be canceled";
static final String ACTION_ID_CANCELED = "id of the action that needs to be canceled (typically identical to id field on the cancel action itself)"; static final String 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 static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.time.Instant;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang3.RandomStringUtils; 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.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status; 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.junit.jupiter.api.Test;
import org.springframework.hateoas.MediaTypes; import org.springframework.hateoas.MediaTypes;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import io.qameta.allure.Description; import io.qameta.allure.Description;
import io.qameta.allure.Feature; import io.qameta.allure.Feature;
@@ -177,11 +184,15 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
final Long actionId = getFirstAssignedActionId(assignDistributionSet(set.getId(), target.getControllerId())); final Long actionId = getFirstAssignedActionId(assignDistributionSet(set.getId(), target.getControllerId()));
final Action cancelAction = deploymentManagement.cancelAction(actionId); 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( mockMvc.perform(post(
DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/" + DdiRestConstants.CANCEL_ACTION DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/" + DdiRestConstants.CANCEL_ACTION
+ "/{actionId}/feedback", + "/{actionId}/feedback",
tenantAware.getCurrentTenant(), target.getControllerId(), cancelAction.getId()).content( tenantAware.getCurrentTenant(), target.getControllerId(), cancelAction.getId()).content(
JsonBuilder.cancelActionFeedback(cancelAction.getId().toString(), "closed", "Some feedback")) objectMapper.writeValueAsString(feedback))
.contentType(MediaType.APPLICATION_JSON_UTF8)) .contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document( .andDo(this.document.document(
@@ -190,7 +201,10 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
parameterWithName("actionId").description(DdiApiModelProperties.ACTION_ID_CANCELED)), parameterWithName("actionId").description(DdiApiModelProperties.ACTION_ID_CANCELED)),
requestFields( requestFields(
optionalRequestFieldWithPath("id") 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").description(DdiApiModelProperties.TARGET_STATUS),
requestFieldWithPath("status.execution") requestFieldWithPath("status.execution")
.description(DdiApiModelProperties.TARGET_EXEC_STATUS).type("enum") .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 Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
final Long actionId = getFirstAssignedActionId(assignDistributionSet(set.getId(), target.getControllerId())); final Long actionId = getFirstAssignedActionId(assignDistributionSet(set.getId(), target.getControllerId()));
mockMvc.perform(post(DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/" final DdiStatus ddiStatus = new DdiStatus(DdiStatus.ExecutionStatus.CLOSED,
+ DdiRestConstants.DEPLOYMENT_BASE_ACTION + "/{actionId}/feedback", tenantAware.getCurrentTenant(), new DdiResult(DdiResult.FinalResult.SUCCESS, new DdiProgress(2, 5)), List.of("Feedback message"));
target.getControllerId(), actionId) final DdiActionFeedback feedback = new DdiActionFeedback(Instant.now().toString(), ddiStatus);
.content(
JsonBuilder.deploymentActionFeedback(actionId.toString(), "closed", "Feedback message")) 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)) .contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document( .andDo(this.document.document(
@@ -395,7 +413,10 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
requestFields( requestFields(
optionalRequestFieldWithPath("id") 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").description(DdiApiModelProperties.TARGET_STATUS),
requestFieldWithPath("status.execution") requestFieldWithPath("status.execution")
.description(DdiApiModelProperties.TARGET_EXEC_STATUS).type("enum") .description(DdiApiModelProperties.TARGET_EXEC_STATUS).type("enum")

53
pom.xml
View File

@@ -16,7 +16,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.7.RELEASE</version> <version>2.3.12.RELEASE</version>
</parent> </parent>
<groupId>org.eclipse.hawkbit</groupId> <groupId>org.eclipse.hawkbit</groupId>
@@ -128,12 +128,11 @@
<properties> <properties>
<java.version>1.8</java.version> <java.version>11</java.version>
<!-- Developer preview: java.version = 11 -->
<spring.boot.version>2.3.7.RELEASE</spring.boot.version> <spring.boot.version>2.3.12.RELEASE</spring.boot.version>
<spring-framework.version>5.2.20.RELEASE</spring-framework.version> <spring-framework.version>5.2.22.RELEASE</spring-framework.version>
<spring.cloud.version>Hoxton.SR7</spring.cloud.version> <spring.cloud.version>Hoxton.SR12</spring.cloud.version>
<spring.plugin.core.version>2.0.0.RELEASE</spring.plugin.core.version> <spring.plugin.core.version>2.0.0.RELEASE</spring.plugin.core.version>
<snapshotDependencyAllowed>true</snapshotDependencyAllowed> <snapshotDependencyAllowed>true</snapshotDependencyAllowed>
@@ -155,15 +154,27 @@
<vaadin.gwt-user.version>2.8.2</vaadin.gwt-user.version> <vaadin.gwt-user.version>2.8.2</vaadin.gwt-user.version>
<!-- Vaadin versions - END --> <!-- Vaadin versions - END -->
<!-- ************************ -->
<!-- Maven Plugins -->
<!-- ************************ -->
<maven.processor.plugin.version>3.3.3</maven.processor.plugin.version> <maven.processor.plugin.version>3.3.3</maven.processor.plugin.version>
<maven.scm.plugin.version>1.11.1</maven.scm.plugin.version> <maven.scm.plugin.version>1.11.1</maven.scm.plugin.version>
<maven.site.plugin.version>3.9.0</maven.site.plugin.version> <maven.site.plugin.version>3.9.1</maven.site.plugin.version>
<maven.surefire.plugin.version>3.0.0-M7</maven.surefire.plugin.version>
<maven.failsafe.plugin.version>3.0.0-M7</maven.failsafe.plugin.version>
<maven.enforcer.plugin.version>3.1.0</maven.enforcer.plugin.version>
<!-- ************************ -->
<!-- Maven Surefire settings -->
<!-- ************************ -->
<surefire.forkcount>1</surefire.forkcount>
<!-- Misc libraries versions - START --> <!-- Misc libraries versions - START -->
<cron-utils.version>9.1.6</cron-utils.version> <cron-utils.version>9.1.6</cron-utils.version>
<jsoup.version>1.15.3</jsoup.version> <jsoup.version>1.15.3</jsoup.version>
<allure.version>2.13.6</allure.version> <allure.version>2.13.6</allure.version>
<eclipselink.version>2.7.9</eclipselink.version> <eclipselink.version>2.7.11</eclipselink.version>
<eclipselink.maven.plugin.version>2.7.9.1</eclipselink.maven.plugin.version>
<jaxb-api.version>2.3.0</jaxb-api.version>
<gwtmockito.version>1.1.8</gwtmockito.version> <gwtmockito.version>1.1.8</gwtmockito.version>
<guava.version>30.1.1-jre</guava.version> <guava.version>30.1.1-jre</guava.version>
<javax.el-api.version>2.2.4</javax.el-api.version> <javax.el-api.version>2.2.4</javax.el-api.version>
@@ -198,13 +209,7 @@
${project.basedir}/../hawkbit-test-report/target/jacoco-aggregate/jacoco.xml, ${project.basedir}/../hawkbit-test-report/target/jacoco-aggregate/jacoco.xml,
${project.basedir}/../../hawkbit-test-report/target/jacoco-aggregate/jacoco.xml ${project.basedir}/../../hawkbit-test-report/target/jacoco-aggregate/jacoco.xml
</sonar.coverage.jacoco.xmlReportPaths> </sonar.coverage.jacoco.xmlReportPaths>
<!-- Sonar - END --> <!-- Sonar - END -->
<!-- ************************ -->
<!-- Maven Surefire settings -->
<!-- ************************ -->
<surefire.forkcount>1</surefire.forkcount>
</properties> </properties>
<build> <build>
@@ -225,6 +230,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId> <artifactId>maven-enforcer-plugin</artifactId>
<version>${maven.enforcer.plugin.version}</version>
<executions> <executions>
<execution> <execution>
<!-- Make sure that only non-snapshot versions are used <!-- Make sure that only non-snapshot versions are used
@@ -404,6 +410,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration> <configuration>
<systemPropertyVariables> <systemPropertyVariables>
<!-- Set output directory according to allure-framework recommendation --> <!-- Set output directory according to allure-framework recommendation -->
@@ -415,9 +422,7 @@
<useSystemClassLoader>false</useSystemClassLoader> <useSystemClassLoader>false</useSystemClassLoader>
<reuseForks>true</reuseForks> <reuseForks>true</reuseForks>
<forkCount>${surefire.forkcount}</forkCount> <forkCount>${surefire.forkcount}</forkCount>
<argLine> <argLine>${jacoco.agent.ut.arg}</argLine>
${jacoco.agent.ut.arg}
</argLine>
<properties> <properties>
<property> <property>
<name>listener</name> <name>listener</name>
@@ -437,6 +442,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId> <artifactId>maven-failsafe-plugin</artifactId>
<version>${maven.failsafe.plugin.version}</version>
<configuration> <configuration>
<reuseForks>false</reuseForks> <reuseForks>false</reuseForks>
<forkCount>${surefire.forkcount}</forkCount> <forkCount>${surefire.forkcount}</forkCount>
@@ -477,6 +483,11 @@
<artifactId>maven-processor-plugin</artifactId> <artifactId>maven-processor-plugin</artifactId>
<version>${maven.processor.plugin.version}</version> <version>${maven.processor.plugin.version}</version>
</plugin> </plugin>
<plugin>
<groupId>com.ethlo.persistence.tools</groupId>
<artifactId>eclipselink-maven-plugin</artifactId>
<version>${eclipselink.maven.plugin.version}</version>
</plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
</build> </build>
@@ -655,7 +666,13 @@
<artifactId>validation-api</artifactId> <artifactId>validation-api</artifactId>
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb-api.version}</version>
</dependency>
<!-- Spring --> <!-- Spring -->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>