Merge pull request #298 from bsinno/feature_target_filtering_supports_overdue
Feature target filtering supports overdue
This commit is contained in:
@@ -9,12 +9,16 @@
|
||||
package org.eclipse.hawkbit.autoconfigure.repository;
|
||||
|
||||
import org.eclipse.hawkbit.EnableJpaRepository;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyResolver;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* Auto-Configuration for enabling the REST-Resources.
|
||||
* Auto-Configuration for enabling JPA repository.
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
@@ -22,4 +26,14 @@ import org.springframework.context.annotation.Import;
|
||||
@Import({ EnableJpaRepository.class })
|
||||
public class JpaRepositoryAutoConfiguration {
|
||||
|
||||
/**
|
||||
*
|
||||
* @return returns a VirtualPropertyReplacer
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public VirtualPropertyReplacer virtualPropertyReplacer() {
|
||||
return new VirtualPropertyResolver();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
|
||||
/**
|
||||
* Encapsulates a set of filters that may be specified (optionally). Properties
|
||||
* that are not specified (e.g. <code>null</code> for simple properties) When
|
||||
* applied, these filters are AND-gated.
|
||||
*
|
||||
*/
|
||||
public class FilterParams {
|
||||
|
||||
private Collection<TargetUpdateStatus> filterByStatus;
|
||||
private Boolean overdueState;
|
||||
private String filterBySearchText;
|
||||
private Boolean selectTargetWithNoTag;
|
||||
private String[] filterByTagNames;
|
||||
private Long filterByDistributionId;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param filterByDistributionId
|
||||
* if set, a filter is added for the given
|
||||
* {@link DistributionSet#getId()}
|
||||
* @param filterByStatus
|
||||
* if set, a filter is added for target states included by the
|
||||
* collection
|
||||
* @param overdueState
|
||||
* if set, a filter is added for overdued devices
|
||||
* @param filterBySearchText
|
||||
* if set, a filter is added for the given search text
|
||||
* @param selectTargetWithNoTag
|
||||
* if set, tag-filtering is enabled
|
||||
* @param filterByTagNames
|
||||
* if tag-filtering is enabled, a filter is added for the given
|
||||
* tag-names
|
||||
*/
|
||||
public FilterParams(Long filterByDistributionId, Collection<TargetUpdateStatus> filterByStatus,
|
||||
Boolean overdueState, String filterBySearchText, Boolean selectTargetWithNoTag,
|
||||
String... filterByTagNames) {
|
||||
this.filterByStatus = filterByStatus;
|
||||
this.overdueState = overdueState;
|
||||
this.filterBySearchText = filterBySearchText;
|
||||
this.filterByDistributionId = filterByDistributionId;
|
||||
this.selectTargetWithNoTag = selectTargetWithNoTag;
|
||||
this.filterByTagNames = filterByTagNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets {@link DistributionSet#getId()} to filter the result. <br>
|
||||
* If set to <code>null</code> this filter is disabled.
|
||||
*
|
||||
* @return {@link DistributionSet#getId()} to filter the result
|
||||
*/
|
||||
public Long getFilterByDistributionId() {
|
||||
return filterByDistributionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link DistributionSet#getId()} to filter the result.
|
||||
*
|
||||
* @param filterByDistributionId
|
||||
* the distribution set id
|
||||
*/
|
||||
public void setFilterByDistributionId(Long filterByDistributionId) {
|
||||
this.filterByDistributionId = filterByDistributionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a collection of target states to filter for. <br>
|
||||
* If set to <code>null</code> this filter is disabled.
|
||||
*
|
||||
* @return collection of target states to filter for
|
||||
*/
|
||||
public Collection<TargetUpdateStatus> getFilterByStatus() {
|
||||
return filterByStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the collection of target states to filter for.
|
||||
*
|
||||
* @param filterByStatus
|
||||
* collection of target update status
|
||||
*/
|
||||
public void setFilterByStatus(Collection<TargetUpdateStatus> filterByStatus) {
|
||||
this.filterByStatus = filterByStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the flag for overdue filter; if set to <code>true</code>, the
|
||||
* overdue filter is activated. Overdued targets a targets that did not
|
||||
* respond during the configured intervals: poll_itvl + overdue_itvl. <br>
|
||||
* If set to <code>null</code> this filter is disabled.
|
||||
*
|
||||
* @return flag for overdue filter activation
|
||||
*/
|
||||
public Boolean getOverdueState() {
|
||||
return overdueState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag for overdue filter; if set to <code>true</code>, the
|
||||
* overdue filter is activated.
|
||||
*
|
||||
* @param overdueState
|
||||
* if the overdue filter should be activates
|
||||
*/
|
||||
public void setOverdueState(Boolean overdueState) {
|
||||
this.overdueState = overdueState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the search text to filter for. This is used to find targets having
|
||||
* the text anywhere in name or description <br>
|
||||
* If set to <code>null</code> this filter is disabled.
|
||||
*
|
||||
* @return the search text to filter for
|
||||
*/
|
||||
public String getFilterBySearchText() {
|
||||
return filterBySearchText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the search text to filter for.
|
||||
*
|
||||
* @param filterBySearchText
|
||||
* search text
|
||||
*/
|
||||
public void setFilterBySearchText(String filterBySearchText) {
|
||||
this.filterBySearchText = filterBySearchText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the flag indicating if tagging filter is used. <br>
|
||||
* If set to <code>null</code> this filter is disabled.
|
||||
*
|
||||
* @return the flag indicating if tagging filter is used
|
||||
*/
|
||||
public Boolean getSelectTargetWithNoTag() {
|
||||
return selectTargetWithNoTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag indicating if tagging filter is used.
|
||||
*
|
||||
* @param selectTargetWithNoTag
|
||||
* should the tagging filter be used?
|
||||
*/
|
||||
public void setSelectTargetWithNoTag(Boolean selectTargetWithNoTag) {
|
||||
this.selectTargetWithNoTag = selectTargetWithNoTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tags that are used to filter for. The activation of this filter
|
||||
* is done by {@link #setSelectTargetWithNoTag(Boolean)}.
|
||||
*
|
||||
* @return the tags that are used to filter for
|
||||
*/
|
||||
public String[] getFilterByTagNames() {
|
||||
return filterByTagNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tags that are used to filter for.
|
||||
*
|
||||
* @param filterByTagNames
|
||||
* array of tag names
|
||||
*/
|
||||
public void setFilterByTagNames(String[] filterByTagNames) {
|
||||
this.filterByTagNames = filterByTagNames;
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,11 @@ public interface TargetManagement {
|
||||
* Count {@link Target}s for all the given filter parameters.
|
||||
*
|
||||
* @param status
|
||||
* find targets having on of these {@link TargetUpdateStatus}s.
|
||||
* 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
|
||||
@@ -86,7 +90,7 @@ public interface TargetManagement {
|
||||
* @return the found number {@link Target}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Long countTargetByFilters(Collection<TargetUpdateStatus> status, String searchText,
|
||||
Long countTargetByFilters(Collection<TargetUpdateStatus> status, Boolean overdueState, String searchText,
|
||||
Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, String... tagNames);
|
||||
|
||||
/**
|
||||
@@ -212,10 +216,12 @@ public interface TargetManagement {
|
||||
*
|
||||
* @param pageRequest
|
||||
* the pageRequest to enhance the query for paging and sorting
|
||||
*
|
||||
* @param filterByStatus
|
||||
* find targets having this {@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).
|
||||
* @param filterBySearchText
|
||||
* to find targets having the text anywhere in name or
|
||||
* description. Set <code>null</code> in case this is not
|
||||
@@ -234,7 +240,7 @@ public interface TargetManagement {
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
List<TargetIdName> findAllTargetIdsByFilters(@NotNull Pageable pageRequest,
|
||||
Collection<TargetUpdateStatus> filterByStatus, String filterBySearchText,
|
||||
Collection<TargetUpdateStatus> filterByStatus, Boolean overdueState, String filterBySearchText,
|
||||
Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, String... filterByTagNames);
|
||||
|
||||
/**
|
||||
@@ -314,7 +320,7 @@ public interface TargetManagement {
|
||||
* given {@code fieldNameProvider}
|
||||
* @throws RSQLParameterSyntaxException
|
||||
* if the RSQL syntax is wrong
|
||||
*
|
||||
*
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET)
|
||||
Page<Target> findTargetByAssignedDistributionSet(@NotNull Long distributionSetID, @NotNull String rsqlParam,
|
||||
@@ -368,6 +374,9 @@ public interface TargetManagement {
|
||||
* @param status
|
||||
* find targets having this {@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).
|
||||
* @param searchText
|
||||
* to find targets having the text anywhere in name or
|
||||
* description. Set <code>null</code> in case this is not
|
||||
@@ -386,7 +395,7 @@ public interface TargetManagement {
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Slice<Target> findTargetByFilters(@NotNull Pageable pageable, Collection<TargetUpdateStatus> status,
|
||||
String searchText, Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag,
|
||||
Boolean overdueState, String searchText, Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag,
|
||||
String... tagNames);
|
||||
|
||||
/**
|
||||
@@ -415,7 +424,7 @@ public interface TargetManagement {
|
||||
* @param pageable
|
||||
* page parameter
|
||||
* @return the found {@link Target}s, never {@code null}
|
||||
*
|
||||
*
|
||||
* @throws RSQLParameterUnsupportedFieldException
|
||||
* if a field in the RSQL string is used but not provided by the
|
||||
* given {@code fieldNameProvider}
|
||||
@@ -460,9 +469,9 @@ public interface TargetManagement {
|
||||
* in string notation
|
||||
* @param pageable
|
||||
* pagination parameter
|
||||
*
|
||||
*
|
||||
* @return the found {@link Target}s, never {@code null}
|
||||
*
|
||||
*
|
||||
* @throws RSQLParameterUnsupportedFieldException
|
||||
* if a field in the RSQL string is used but not provided by the
|
||||
* given {@code fieldNameProvider}
|
||||
@@ -481,9 +490,9 @@ public interface TargetManagement {
|
||||
* the specification for the query
|
||||
* @param pageable
|
||||
* pagination parameter
|
||||
*
|
||||
*
|
||||
* @return the found {@link Target}s, never {@code null}
|
||||
*
|
||||
*
|
||||
* @throws RSQLParameterUnsupportedFieldException
|
||||
* if a field in the RSQL string is used but not provided by the
|
||||
* given {@code fieldNameProvider}
|
||||
@@ -511,33 +520,15 @@ public interface TargetManagement {
|
||||
* the page request to page the result set
|
||||
* @param orderByDistributionId
|
||||
* {@link DistributionSet#getId()} to be ordered by
|
||||
* @param filterByDistributionId
|
||||
* {@link DistributionSet#getId()} to be filter the result. Set
|
||||
* to <code>null</code> in case this is not required.
|
||||
* @param filterByStatus
|
||||
* find targets having this {@link TargetUpdateStatus}s. Set to
|
||||
* <code>null</code> in case this is not required.
|
||||
* @param filterBySearchText
|
||||
* 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 filterByTagNames
|
||||
* 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
|
||||
* @param filterParams
|
||||
* the filters to apply; only filters are enabled that have
|
||||
* non-null value; filters are AND-gated
|
||||
* @return a paged result {@link Page} of the {@link Target}s in a defined
|
||||
* order.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Slice<Target> findTargetsAllOrderByLinkedDistributionSet(@NotNull Pageable pageable,
|
||||
@NotNull Long orderByDistributionId, Long filterByDistributionId,
|
||||
Collection<TargetUpdateStatus> filterByStatus, String filterBySearchText, Boolean selectTargetWithNoTag,
|
||||
String... filterByTagNames);
|
||||
@NotNull Long orderByDistributionId, FilterParams filterParams);
|
||||
|
||||
/**
|
||||
* retrieves a list of {@link Target}s by their controller ID with details,
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.rsql;
|
||||
|
||||
/**
|
||||
* Implementations map a placeholder to the associated value.
|
||||
* <p>
|
||||
* This is used in context of string replacement.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface VirtualPropertyReplacer {
|
||||
|
||||
/**
|
||||
* Looks up a placeholders and replaces them
|
||||
*
|
||||
* @param input
|
||||
* the input string in which virtual properties should be
|
||||
* replaced
|
||||
* @return the result of the replacement
|
||||
*/
|
||||
String replace(String input);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
|
||||
/**
|
||||
* Calculates non-persistent timestamps , e.g. the point a time a
|
||||
* target is declared as overdue.<br>
|
||||
* Therefore tenant specific configuration may be considered.
|
||||
*
|
||||
*/
|
||||
public final class TimestampCalculator {
|
||||
|
||||
private TimestampCalculator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the overdue timestamp (<em>overdue_ts</em>) based on the
|
||||
* current timestamp and the intervals for polling and poll-overdue:
|
||||
* <p>
|
||||
* <em>overdue_ts = now_ts - pollingInterval -
|
||||
* pollingOverdueInterval</em>;<br>
|
||||
* <em>pollingInterval</em> and <em>pollingOverdueInterval</em> are
|
||||
* retrieved from tenant-specific system configuration.
|
||||
*
|
||||
* @return <em>overdue_ts</em> in milliseconds since Unix epoch as long
|
||||
* value
|
||||
*/
|
||||
public static long calculateOverdueTimestamp() {
|
||||
return Instant.now().toEpochMilli() - getDurationForKey(TenantConfigurationKey.POLLING_TIME_INTERVAL).toMillis()
|
||||
- getDurationForKey(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL).toMillis();
|
||||
}
|
||||
|
||||
private static Duration getDurationForKey(TenantConfigurationKey key) {
|
||||
return DurationHelper.formattedStringToDuration(getRawStringForKey(key));
|
||||
}
|
||||
|
||||
private static String getRawStringForKey(TenantConfigurationKey key) {
|
||||
return getTenantConfigurationManagement().getConfigurationValue(key, String.class).getValue();
|
||||
}
|
||||
|
||||
public static TenantConfigurationManagement getTenantConfigurationManagement() {
|
||||
return TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.rsql;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.apache.commons.lang3.text.StrLookup;
|
||||
import org.apache.commons.lang3.text.StrSubstitutor;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.TimestampCalculator;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
|
||||
/**
|
||||
* Adds macro capabilities to RSQL expressions that are used to filter for
|
||||
* targets.
|
||||
* <p>
|
||||
* Some (virtual) properties do not have a representation in the database (in
|
||||
* general these properties are time-related, or more explicitly, they deal with
|
||||
* time intervals).<br>
|
||||
* Such a virtual property needs to be calculated on Java-side before it may be
|
||||
* used in a target filter query that is passed to the database. Therefore a
|
||||
* placeholder is used in the RSQL expression that is expanded when the RSQL is
|
||||
* parsed
|
||||
* <p>
|
||||
* A virtual property may either be a system value like the current date (aka
|
||||
* <em>now_ts</em>) or a value derived from (tenant-specific) system
|
||||
* configuration (e.g. <em>overdue_ts</em>).
|
||||
* <p>
|
||||
* Known values are:<br>
|
||||
* <ul>
|
||||
* <li><em>now_ts</em>: maps to system UTC time in milliseconds since Unix epoch
|
||||
* as long value</li>
|
||||
* <li><em>overdue_ts</em>: is a calculated value: <em>overdue_ts = now_ts -
|
||||
* pollingInterval - pollingOverdueInterval</em>; pollingInterval and
|
||||
* pollingOverdueInterval are retrieved from tenant-specific system
|
||||
* configuration.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class VirtualPropertyResolver extends StrLookup<String> implements VirtualPropertyReplacer {
|
||||
|
||||
private StrSubstitutor substitutor;
|
||||
|
||||
@Override
|
||||
public String lookup(String rhs) {
|
||||
String resolved = null;
|
||||
|
||||
if ("now_ts".equalsIgnoreCase(rhs)) {
|
||||
resolved = String.valueOf(Instant.now().toEpochMilli());
|
||||
} else if ("overdue_ts".equalsIgnoreCase(rhs)) {
|
||||
resolved = String.valueOf(TimestampCalculator.calculateOverdueTimestamp());
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String replace(String input) {
|
||||
if (substitutor == null) {
|
||||
substitutor = new StrSubstitutor(this, StrSubstitutor.DEFAULT_PREFIX, StrSubstitutor.DEFAULT_SUFFIX,
|
||||
StrSubstitutor.DEFAULT_ESCAPE);
|
||||
}
|
||||
return substitutor.replace(input);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -141,6 +141,16 @@
|
||||
<artifactId>fest-assert</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -172,7 +172,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return the singleton instance of the
|
||||
* {@link AfterTransactionCommitExecutorHolder}
|
||||
*/
|
||||
@@ -234,7 +234,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaSystemManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link SystemManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -245,7 +245,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaReportManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link ReportManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -256,7 +256,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaDistributionSetManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link DistributionSetManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -267,7 +267,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaTenantStatsManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link TenantStatsManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -280,7 +280,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaTenantConfigurationManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link TenantConfigurationManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -291,7 +291,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaTenantConfigurationManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link TenantConfigurationManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -302,7 +302,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaTargetFilterQueryManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link TargetFilterQueryManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -313,7 +313,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaTagManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link TagManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -324,7 +324,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaSoftwareManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link SoftwareManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -335,7 +335,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaRolloutManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link RolloutManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -346,7 +346,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaRolloutGroupManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link RolloutGroupManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -357,7 +357,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaDeploymentManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link DeploymentManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -368,7 +368,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaControllerManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link ControllerManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -379,7 +379,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaArtifactManagement} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link ArtifactManagement}
|
||||
*/
|
||||
|
||||
@@ -391,7 +391,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link JpaEntityFactory} bean.
|
||||
*
|
||||
*
|
||||
* @return a new {@link EntityFactory}
|
||||
*/
|
||||
@Bean
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
@@ -135,6 +136,9 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
@Autowired
|
||||
private SystemSecurityContext systemSecurityContext;
|
||||
|
||||
@Autowired
|
||||
private VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
@Override
|
||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||
@Modifying
|
||||
@@ -607,8 +611,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
return convertAcPage(actions, pageable);
|
||||
}
|
||||
|
||||
private static Specification<JpaAction> createSpecificationFor(final Target target, final String rsqlParam) {
|
||||
final Specification<JpaAction> spec = RSQLUtility.parse(rsqlParam, ActionFields.class);
|
||||
private Specification<JpaAction> createSpecificationFor(final Target target, final String rsqlParam) {
|
||||
final Specification<JpaAction> spec = RSQLUtility.parse(rsqlParam, ActionFields.class, virtualPropertyReplacer);
|
||||
return (root, query, cb) -> cb.and(spec.toPredicate(root, query, cb),
|
||||
cb.equal(root.get(JpaAction_.target), target));
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
@@ -110,6 +111,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
@Autowired
|
||||
private TenantAware tenantAware;
|
||||
|
||||
@Autowired
|
||||
private VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
@Override
|
||||
public DistributionSet findDistributionSetByIdWithDetails(final Long distid) {
|
||||
return distributionSetRepository.findOne(DistributionSetSpecification.byId(distid));
|
||||
@@ -286,7 +290,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
@Override
|
||||
public Page<DistributionSetType> findDistributionSetTypesAll(final String rsqlParam, final Pageable pageable) {
|
||||
final Specification<JpaDistributionSetType> spec = RSQLUtility.parse(rsqlParam,
|
||||
DistributionSetTypeFields.class);
|
||||
DistributionSetTypeFields.class, virtualPropertyReplacer);
|
||||
|
||||
return convertDsTPage(distributionSetTypeRepository.findAll(spec, pageable));
|
||||
}
|
||||
@@ -352,7 +356,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
public Page<DistributionSet> findDistributionSetsAll(final String rsqlParam, final Pageable pageReq,
|
||||
final Boolean deleted) {
|
||||
|
||||
final Specification<JpaDistributionSet> spec = RSQLUtility.parse(rsqlParam, DistributionSetFields.class);
|
||||
final Specification<JpaDistributionSet> spec = RSQLUtility.parse(rsqlParam, DistributionSetFields.class,
|
||||
virtualPropertyReplacer);
|
||||
|
||||
final List<Specification<JpaDistributionSet>> specList = new ArrayList<>(2);
|
||||
if (deleted != null) {
|
||||
@@ -528,7 +533,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
/**
|
||||
* Method to get the latest distribution set based on ds ID after the
|
||||
* metadata changes for that distribution set.
|
||||
*
|
||||
*
|
||||
* @param distributionSet
|
||||
* Distribution set
|
||||
*/
|
||||
@@ -564,7 +569,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
final String rsqlParam, final Pageable pageable) {
|
||||
|
||||
final Specification<JpaDistributionSetMetadata> spec = RSQLUtility.parse(rsqlParam,
|
||||
DistributionSetMetadataFields.class);
|
||||
DistributionSetMetadataFields.class, virtualPropertyReplacer);
|
||||
|
||||
return convertMdPage(
|
||||
distributionSetMetadataRepository
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup_;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
|
||||
@@ -70,6 +71,9 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
private VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
@Override
|
||||
public RolloutGroup findRolloutGroupById(final Long rolloutGroupId) {
|
||||
return rolloutGroupRepository.findOne(rolloutGroupId);
|
||||
@@ -92,7 +96,8 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
||||
public Page<RolloutGroup> findRolloutGroupsAll(final Rollout rollout, final String rsqlParam,
|
||||
final Pageable pageable) {
|
||||
|
||||
final Specification<JpaRolloutGroup> specification = RSQLUtility.parse(rsqlParam, RolloutGroupFields.class);
|
||||
final Specification<JpaRolloutGroup> specification = RSQLUtility.parse(rsqlParam, RolloutGroupFields.class,
|
||||
virtualPropertyReplacer);
|
||||
|
||||
return convertPage(
|
||||
rolloutGroupRepository
|
||||
@@ -145,7 +150,8 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
||||
public Page<Target> findRolloutGroupTargets(final RolloutGroup rolloutGroup, final String rsqlParam,
|
||||
final Pageable pageable) {
|
||||
|
||||
final Specification<JpaTarget> rsqlSpecification = RSQLUtility.parse(rsqlParam, TargetFields.class);
|
||||
final Specification<JpaTarget> rsqlSpecification = RSQLUtility.parse(rsqlParam, TargetFields.class,
|
||||
virtualPropertyReplacer);
|
||||
|
||||
return convertTPage(targetRepository.findAll((root, query, criteriaBuilder) -> {
|
||||
final ListJoin<JpaTarget, RolloutTargetGroup> rolloutTargetJoin = root.join(JpaTarget_.rolloutTargetGroup);
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupActionEvaluator;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupConditionEvaluator;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -114,6 +115,9 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
@Autowired
|
||||
private CacheWriteNotify cacheWriteNotify;
|
||||
|
||||
@Autowired
|
||||
private VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("asyncExecutor")
|
||||
private Executor executor;
|
||||
@@ -150,7 +154,8 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
@Override
|
||||
public Page<Rollout> findAllWithDetailedStatusByPredicate(final String rsqlParam, final Pageable pageable) {
|
||||
|
||||
final Specification<JpaRollout> specification = RSQLUtility.parse(rsqlParam, RolloutFields.class);
|
||||
final Specification<JpaRollout> specification = RSQLUtility.parse(rsqlParam, RolloutFields.class,
|
||||
virtualPropertyReplacer);
|
||||
|
||||
final Page<JpaRollout> findAll = rolloutRepository.findAll(specification, pageable);
|
||||
setRolloutStatusDetails(findAll);
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule;
|
||||
@@ -106,6 +107,9 @@ public class JpaSoftwareManagement implements SoftwareManagement {
|
||||
@Autowired
|
||||
private ArtifactManagement artifactManagement;
|
||||
|
||||
@Autowired
|
||||
private VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
@Override
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
@@ -312,7 +316,8 @@ public class JpaSoftwareManagement implements SoftwareManagement {
|
||||
|
||||
@Override
|
||||
public Page<SoftwareModule> findSoftwareModulesByPredicate(final String rsqlParam, final Pageable pageable) {
|
||||
final Specification<JpaSoftwareModule> spec = RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class);
|
||||
final Specification<JpaSoftwareModule> spec = RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class,
|
||||
virtualPropertyReplacer);
|
||||
|
||||
return convertSmPage(softwareModuleRepository.findAll(spec, pageable), pageable);
|
||||
}
|
||||
@@ -320,7 +325,8 @@ public class JpaSoftwareManagement implements SoftwareManagement {
|
||||
@Override
|
||||
public Page<SoftwareModuleType> findSoftwareModuleTypesAll(final String rsqlParam, final Pageable pageable) {
|
||||
|
||||
final Specification<JpaSoftwareModuleType> spec = RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class);
|
||||
final Specification<JpaSoftwareModuleType> spec = RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class,
|
||||
virtualPropertyReplacer);
|
||||
|
||||
return convertSmTPage(softwareModuleTypeRepository.findAll(spec, pageable), pageable);
|
||||
}
|
||||
@@ -606,7 +612,7 @@ public class JpaSoftwareManagement implements SoftwareManagement {
|
||||
final String rsqlParam, final Pageable pageable) {
|
||||
|
||||
final Specification<JpaSoftwareModuleMetadata> spec = RSQLUtility.parse(rsqlParam,
|
||||
SoftwareModuleMetadataFields.class);
|
||||
SoftwareModuleMetadataFields.class, virtualPropertyReplacer);
|
||||
return convertSmMdPage(
|
||||
softwareModuleMetadataRepository
|
||||
.findAll(
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
@@ -74,6 +75,9 @@ public class JpaTagManagement implements TagManagement {
|
||||
@Autowired
|
||||
private AfterTransactionCommitExecutor afterCommit;
|
||||
|
||||
@Autowired
|
||||
private VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
@Override
|
||||
public TargetTag findTargetTag(final String name) {
|
||||
return targetTagRepository.findByNameEquals(name);
|
||||
@@ -145,7 +149,7 @@ public class JpaTagManagement implements TagManagement {
|
||||
@Override
|
||||
public Page<TargetTag> findAllTargetTags(final String rsqlParam, final Pageable pageable) {
|
||||
|
||||
final Specification<JpaTargetTag> spec = RSQLUtility.parse(rsqlParam, TagFields.class);
|
||||
final Specification<JpaTargetTag> spec = RSQLUtility.parse(rsqlParam, TagFields.class, virtualPropertyReplacer);
|
||||
return convertTPage(targetTagRepository.findAll(spec, pageable), pageable);
|
||||
}
|
||||
|
||||
@@ -276,7 +280,8 @@ public class JpaTagManagement implements TagManagement {
|
||||
|
||||
@Override
|
||||
public Page<DistributionSetTag> findAllDistributionSetTags(final String rsqlParam, final Pageable pageable) {
|
||||
final Specification<JpaDistributionSetTag> spec = RSQLUtility.parse(rsqlParam, TagFields.class);
|
||||
final Specification<JpaDistributionSetTag> spec = RSQLUtility.parse(rsqlParam, TagFields.class,
|
||||
virtualPropertyReplacer);
|
||||
|
||||
return convertDsPage(distributionSetTagRepository.findAll(spec, pageable), pageable);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetFilterQuerySpecification;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -49,6 +50,9 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
@Autowired
|
||||
private TargetFilterQueryRepository targetFilterQueryRepository;
|
||||
|
||||
@Autowired
|
||||
private VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
@Override
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
@@ -95,7 +99,8 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
public Page<TargetFilterQuery> findTargetFilterQueryByFilter(@NotNull Pageable pageable, String rsqlFilter) {
|
||||
List<Specification<JpaTargetFilterQuery>> specList = Collections.emptyList();
|
||||
if (!Strings.isNullOrEmpty(rsqlFilter)) {
|
||||
specList = Collections.singletonList(RSQLUtility.parse(rsqlFilter, TargetFilterQueryFields.class));
|
||||
specList = Collections.singletonList(
|
||||
RSQLUtility.parse(rsqlFilter, TargetFilterQueryFields.class, virtualPropertyReplacer));
|
||||
}
|
||||
return convertPage(findTargetFilterQueryByCriteriaAPI(pageable, specList), pageable);
|
||||
}
|
||||
@@ -114,7 +119,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
specList.add(TargetFilterQuerySpecification.byAutoAssignDS(distributionSet));
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(rsqlFilter)) {
|
||||
specList.add(RSQLUtility.parse(rsqlFilter, TargetFilterQueryFields.class));
|
||||
specList.add(RSQLUtility.parse(rsqlFilter, TargetFilterQueryFields.class, virtualPropertyReplacer));
|
||||
}
|
||||
return convertPage(findTargetFilterQueryByCriteriaAPI(pageable, specList), pageable);
|
||||
}
|
||||
@@ -156,7 +161,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
|
||||
@Override
|
||||
public boolean verifyTargetFilterQuerySyntax(final String query) {
|
||||
RSQLUtility.parse(query, TargetFields.class);
|
||||
RSQLUtility.parse(query, TargetFields.class, virtualPropertyReplacer);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -29,6 +28,8 @@ import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.hawkbit.repository.FilterParams;
|
||||
import org.eclipse.hawkbit.repository.TargetFields;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent;
|
||||
@@ -43,6 +44,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
@@ -68,7 +70,6 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
@@ -104,6 +105,9 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Autowired
|
||||
private AfterTransactionCommitExecutor afterCommit;
|
||||
|
||||
@Autowired
|
||||
private VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
@Override
|
||||
public Target findTargetByControllerID(final String controllerId) {
|
||||
return targetRepository.findByControllerId(controllerId);
|
||||
@@ -154,12 +158,15 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Slice<Target> findTargetsAll(final TargetFilterQuery targetFilterQuery, final Pageable pageable) {
|
||||
return findTargetsBySpec(RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class), pageable);
|
||||
return findTargetsBySpec(
|
||||
RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, virtualPropertyReplacer),
|
||||
pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Target> findTargetsAll(final String targetFilterQuery, final Pageable pageable) {
|
||||
return findTargetsBySpec(RSQLUtility.parse(targetFilterQuery, TargetFields.class), pageable);
|
||||
return findTargetsBySpec(RSQLUtility.parse(targetFilterQuery, TargetFields.class, virtualPropertyReplacer),
|
||||
pageable);
|
||||
}
|
||||
|
||||
private Page<Target> findTargetsBySpec(final Specification<JpaTarget> spec, final Pageable pageable) {
|
||||
@@ -223,7 +230,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
public Page<Target> findTargetByAssignedDistributionSet(final Long distributionSetID, final String rsqlParam,
|
||||
final Pageable pageReq) {
|
||||
|
||||
final Specification<JpaTarget> spec = RSQLUtility.parse(rsqlParam, TargetFields.class);
|
||||
final Specification<JpaTarget> spec = RSQLUtility.parse(rsqlParam, TargetFields.class,
|
||||
virtualPropertyReplacer);
|
||||
|
||||
return convertPage(
|
||||
targetRepository
|
||||
@@ -251,7 +259,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
public Page<Target> findTargetByInstalledDistributionSet(final Long distributionSetId, final String rsqlParam,
|
||||
final Pageable pageable) {
|
||||
|
||||
final Specification<JpaTarget> spec = RSQLUtility.parse(rsqlParam, TargetFields.class);
|
||||
final Specification<JpaTarget> spec = RSQLUtility.parse(rsqlParam, TargetFields.class,
|
||||
virtualPropertyReplacer);
|
||||
|
||||
return convertPage(
|
||||
targetRepository
|
||||
@@ -269,42 +278,56 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Slice<Target> findTargetByFilters(final Pageable pageable, final Collection<TargetUpdateStatus> status,
|
||||
final String searchText, final Long installedOrAssignedDistributionSetId,
|
||||
final Boolean overdueState, final String searchText, final Long installedOrAssignedDistributionSetId,
|
||||
final Boolean selectTargetWithNoTag, final String... tagNames) {
|
||||
final List<Specification<JpaTarget>> specList = buildSpecificationList(status, searchText,
|
||||
installedOrAssignedDistributionSetId, selectTargetWithNoTag, true, tagNames);
|
||||
final List<Specification<JpaTarget>> specList = buildSpecificationList(
|
||||
new FilterParams(installedOrAssignedDistributionSetId, status, overdueState, searchText,
|
||||
selectTargetWithNoTag, tagNames),
|
||||
true);
|
||||
return findByCriteriaAPI(pageable, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countTargetByFilters(final Collection<TargetUpdateStatus> status, final String searchText,
|
||||
final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag,
|
||||
final String... tagNames) {
|
||||
final List<Specification<JpaTarget>> specList = buildSpecificationList(status, searchText,
|
||||
installedOrAssignedDistributionSetId, selectTargetWithNoTag, true, tagNames);
|
||||
public Long countTargetByFilters(final Collection<TargetUpdateStatus> status, final Boolean overdueState,
|
||||
final String searchText, final Long installedOrAssignedDistributionSetId,
|
||||
final Boolean selectTargetWithNoTag, final String... tagNames) {
|
||||
final List<Specification<JpaTarget>> specList = buildSpecificationList(
|
||||
new FilterParams(installedOrAssignedDistributionSetId, status, overdueState, searchText,
|
||||
selectTargetWithNoTag, tagNames),
|
||||
true);
|
||||
return countByCriteriaAPI(specList);
|
||||
}
|
||||
|
||||
private static List<Specification<JpaTarget>> buildSpecificationList(final Collection<TargetUpdateStatus> status,
|
||||
final String searchText, final Long installedOrAssignedDistributionSetId,
|
||||
final Boolean selectTargetWithNoTag, final boolean fetch, final String... tagNames) {
|
||||
final List<Specification<JpaTarget>> specList = new LinkedList<>();
|
||||
if (status != null && !status.isEmpty()) {
|
||||
specList.add(TargetSpecifications.hasTargetUpdateStatus(status, fetch));
|
||||
private static List<Specification<JpaTarget>> buildSpecificationList(final FilterParams filterParams,
|
||||
final boolean fetch) {
|
||||
final List<Specification<JpaTarget>> specList = new ArrayList<>();
|
||||
if (filterParams.getFilterByStatus() != null && !filterParams.getFilterByStatus().isEmpty()) {
|
||||
specList.add(TargetSpecifications.hasTargetUpdateStatus(filterParams.getFilterByStatus(), fetch));
|
||||
}
|
||||
if (installedOrAssignedDistributionSetId != null) {
|
||||
if (filterParams.getOverdueState() != null) {
|
||||
specList.add(
|
||||
TargetSpecifications.hasInstalledOrAssignedDistributionSet(installedOrAssignedDistributionSetId));
|
||||
TargetSpecifications.isOverdue(TimestampCalculator.calculateOverdueTimestamp()));
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(searchText)) {
|
||||
specList.add(TargetSpecifications.likeNameOrDescriptionOrIp(searchText));
|
||||
if (filterParams.getFilterByDistributionId() != null) {
|
||||
specList.add(
|
||||
TargetSpecifications
|
||||
.hasInstalledOrAssignedDistributionSet(filterParams.getFilterByDistributionId()));
|
||||
}
|
||||
if (selectTargetWithNoTag != null && (selectTargetWithNoTag || (tagNames != null && tagNames.length > 0))) {
|
||||
specList.add(TargetSpecifications.hasTags(tagNames, selectTargetWithNoTag));
|
||||
if (StringUtils.isNotEmpty(filterParams.getFilterBySearchText())) {
|
||||
specList.add(TargetSpecifications.likeNameOrDescriptionOrIp(filterParams.getFilterBySearchText()));
|
||||
}
|
||||
if (isHasTagsFilterActive(filterParams)) {
|
||||
specList.add(TargetSpecifications.hasTags(filterParams.getFilterByTagNames(),
|
||||
filterParams.getSelectTargetWithNoTag()));
|
||||
}
|
||||
return specList;
|
||||
}
|
||||
|
||||
private static boolean isHasTagsFilterActive(final FilterParams filterParams) {
|
||||
return filterParams.getSelectTargetWithNoTag() != null && (filterParams.getSelectTargetWithNoTag()
|
||||
|| (filterParams.getFilterByTagNames() != null && filterParams.getFilterByTagNames().length > 0));
|
||||
}
|
||||
|
||||
private Slice<Target> findByCriteriaAPI(final Pageable pageable, final List<Specification<JpaTarget>> specList) {
|
||||
if (specList == null || specList.isEmpty()) {
|
||||
return convertPage(criteriaNoCountDao.findAll(pageable, JpaTarget.class), pageable);
|
||||
@@ -418,9 +441,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Slice<Target> findTargetsAllOrderByLinkedDistributionSet(final Pageable pageable,
|
||||
final Long orderByDistributionId, final Long filterByDistributionId,
|
||||
final Collection<TargetUpdateStatus> filterByStatus, final String filterBySearchText,
|
||||
final Boolean selectTargetWithNoTag, final String... filterByTagNames) {
|
||||
final Long orderByDistributionId, final FilterParams filterParams) {
|
||||
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<JpaTarget> query = cb.createQuery(JpaTarget.class);
|
||||
final Root<JpaTarget> targetRoot = query.from(JpaTarget.class);
|
||||
@@ -443,8 +465,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
// build the specifications and then to predicates necessary by the
|
||||
// given filters
|
||||
final Predicate[] specificationsForMultiSelect = specificationsToPredicate(
|
||||
buildSpecificationList(filterByStatus, filterBySearchText, filterByDistributionId,
|
||||
selectTargetWithNoTag, true, filterByTagNames),
|
||||
buildSpecificationList(filterParams, true),
|
||||
targetRoot, query, cb);
|
||||
|
||||
// if we have some predicates then add it to the where clause of the
|
||||
@@ -500,7 +521,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public List<TargetIdName> findAllTargetIdsByFilters(final Pageable pageRequest,
|
||||
final Collection<TargetUpdateStatus> filterByStatus, final String filterBySearchText,
|
||||
final Collection<TargetUpdateStatus> filterByStatus, final Boolean overdueState,
|
||||
final String filterBySearchText,
|
||||
final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag,
|
||||
final String... filterByTagNames) {
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
@@ -517,8 +539,9 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
targetRoot.get(JpaTarget_.controllerId), targetRoot.get(JpaTarget_.name), targetRoot.get(sortProperty));
|
||||
|
||||
final Predicate[] specificationsForMultiSelect = specificationsToPredicate(
|
||||
buildSpecificationList(filterByStatus, filterBySearchText, installedOrAssignedDistributionSetId,
|
||||
selectTargetWithNoTag, false, filterByTagNames),
|
||||
buildSpecificationList(new FilterParams(installedOrAssignedDistributionSetId, filterByStatus,
|
||||
overdueState, filterBySearchText,
|
||||
selectTargetWithNoTag, filterByTagNames), false),
|
||||
targetRoot, multiselect, cb);
|
||||
|
||||
// if we have some predicates then add it to the where clause of the
|
||||
@@ -547,7 +570,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
final CriteriaQuery<Object[]> multiselect = query.multiselect(targetRoot.get(JpaTarget_.id),
|
||||
targetRoot.get(JpaTarget_.controllerId), targetRoot.get(JpaTarget_.name), targetRoot.get(sortProperty));
|
||||
|
||||
final Specification<JpaTarget> spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class);
|
||||
final Specification<JpaTarget> spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class,
|
||||
virtualPropertyReplacer);
|
||||
final Predicate[] specificationsForMultiSelect = specificationsToPredicate(Lists.newArrayList(spec), targetRoot,
|
||||
multiselect, cb);
|
||||
|
||||
@@ -565,7 +589,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
public Page<Target> findAllTargetsByTargetFilterQueryAndNonDS(@NotNull final Pageable pageRequest,
|
||||
final Long distributionSetId, @NotNull final TargetFilterQuery targetFilterQuery) {
|
||||
|
||||
final Specification<JpaTarget> spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class);
|
||||
final Specification<JpaTarget> spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class,
|
||||
virtualPropertyReplacer);
|
||||
|
||||
return findTargetsBySpec(
|
||||
(root, cq,
|
||||
@@ -578,7 +603,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Override
|
||||
public Long countTargetsByTargetFilterQueryAndNonDS(final Long distributionSetId,
|
||||
@NotNull final TargetFilterQuery targetFilterQuery) {
|
||||
final Specification<JpaTarget> spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class);
|
||||
final Specification<JpaTarget> spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class,
|
||||
virtualPropertyReplacer);
|
||||
final List<Specification<JpaTarget>> specList = new ArrayList<>(2);
|
||||
specList.add(spec);
|
||||
specList.add(TargetSpecifications.hasNotDistributionSetInActions(distributionSetId));
|
||||
@@ -650,13 +676,15 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Long countTargetByTargetFilterQuery(final TargetFilterQuery targetFilterQuery) {
|
||||
final Specification<JpaTarget> specs = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class);
|
||||
final Specification<JpaTarget> specs = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class,
|
||||
virtualPropertyReplacer);
|
||||
return targetRepository.count(specs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countTargetByTargetFilterQuery(final String targetFilterQuery) {
|
||||
final Specification<JpaTarget> specs = RSQLUtility.parse(targetFilterQuery, TargetFields.class);
|
||||
final Specification<JpaTarget> specs = RSQLUtility.parse(targetFilterQuery, TargetFields.class,
|
||||
virtualPropertyReplacer);
|
||||
return targetRepository.count(specs);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,10 +25,12 @@ import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.apache.commons.lang3.text.StrLookup;
|
||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
||||
import org.eclipse.hawkbit.repository.FieldValueConverter;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.SimpleTypeConverter;
|
||||
@@ -47,9 +49,8 @@ import cz.jirutka.rsql.parser.ast.RSQLOperators;
|
||||
import cz.jirutka.rsql.parser.ast.RSQLVisitor;
|
||||
|
||||
/**
|
||||
* A utility class which is able to parse RSQL strings into an spring data
|
||||
* {@link Specification} which then can be enhanced sql queries to filter
|
||||
* entities. RSQL parser library: https://github.com/jirutka/rsql-parser
|
||||
* A utility class which is able to parse RSQL strings into an spring data {@link Specification} which then can be
|
||||
* enhanced sql queries to filter entities. RSQL parser library: https://github.com/jirutka/rsql-parser
|
||||
*
|
||||
* <ul>
|
||||
* <li>Equal to : ==</li>
|
||||
@@ -59,16 +60,24 @@ import cz.jirutka.rsql.parser.ast.RSQLVisitor;
|
||||
* <li>Greater than operator : =gt= or ></li>
|
||||
* <li>Greater than or equal to : =ge= or >=</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Examples of RSQL expressions in both FIQL-like and alternative notation:
|
||||
* <ul>
|
||||
* <li>version==2.0.0</li>
|
||||
* <li>name==targetId1;description==plugAndPlay</li>
|
||||
* <li>name==targetId1 and description==plugAndPlay</li>
|
||||
* <li>name==targetId1;description==plugAndPlay</li>
|
||||
* <li>name==targetId1 and description==plugAndPlay</li>
|
||||
* <li>name==targetId1,description==plugAndPlay,updateStatus==UNKNOWN</li>
|
||||
* <li>name==targetId1 or description==plugAndPlay or updateStatus==UNKNOWN</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* There is also a mechanism that allows to refer to known macros that can resolved by an optional {@link StrLookup}
|
||||
* (cp. {@link VirtualPropertyResolver}).<br>
|
||||
* An example that queries for all overdue targets using the ${OVERDUE_TS} placeholder introduced by
|
||||
* {@link VirtualPropertyResolver} looks like this:<br>
|
||||
* <em>lastControllerRequestAt=le=${OVERDUE_TS}</em><br>
|
||||
* It is possible to escape a macro expression by using a second '$': $${OVERDUE_TS} would prevent the ${OVERDUE_TS}
|
||||
* token from being expanded.
|
||||
*
|
||||
*/
|
||||
public final class RSQLUtility {
|
||||
|
||||
@@ -90,6 +99,9 @@ public final class RSQLUtility {
|
||||
* @param fieldNameProvider
|
||||
* the enum class type which implements the
|
||||
* {@link FieldNameProvider}
|
||||
* @param virtualPropertyReplacer
|
||||
* holds the logic how the known macros have to be resolved; may
|
||||
* be <code>null</code>
|
||||
* @return an specification which can be used with JPA
|
||||
* @throws RSQLParameterUnsupportedFieldException
|
||||
* if a field in the RSQL string is used but not provided by the
|
||||
@@ -98,8 +110,8 @@ public final class RSQLUtility {
|
||||
* if the RSQL syntax is wrong
|
||||
*/
|
||||
public static <A extends Enum<A> & FieldNameProvider, T> Specification<T> parse(final String rsql,
|
||||
final Class<A> fieldNameProvider) {
|
||||
return new RSQLSpecification<>(rsql.toLowerCase(), fieldNameProvider);
|
||||
final Class<A> fieldNameProvider, VirtualPropertyReplacer virtualPropertyReplacer) {
|
||||
return new RSQLSpecification<>(rsql.toLowerCase(), fieldNameProvider, virtualPropertyReplacer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,10 +142,13 @@ public final class RSQLUtility {
|
||||
|
||||
private final String rsql;
|
||||
private final Class<A> enumType;
|
||||
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
private RSQLSpecification(final String rsql, final Class<A> enumType) {
|
||||
private RSQLSpecification(final String rsql, final Class<A> enumType,
|
||||
VirtualPropertyReplacer virtualPropertyReplacer) {
|
||||
this.rsql = rsql;
|
||||
this.enumType = enumType;
|
||||
this.virtualPropertyReplacer = virtualPropertyReplacer;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,7 +156,8 @@ public final class RSQLUtility {
|
||||
|
||||
final Node rootNode = parseRsql(rsql);
|
||||
|
||||
final JpqQueryRSQLVisitor<A, T> jpqQueryRSQLVisitor = new JpqQueryRSQLVisitor<>(root, cb, enumType);
|
||||
final JpqQueryRSQLVisitor<A, T> jpqQueryRSQLVisitor = new JpqQueryRSQLVisitor<>(root, cb, enumType,
|
||||
virtualPropertyReplacer);
|
||||
final List<Predicate> accept = rootNode.<List<Predicate>, String> accept(jpqQueryRSQLVisitor);
|
||||
|
||||
if (accept != null && !accept.isEmpty()) {
|
||||
@@ -171,13 +187,16 @@ public final class RSQLUtility {
|
||||
private final Root<T> root;
|
||||
private final CriteriaBuilder cb;
|
||||
private final Class<A> enumType;
|
||||
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
private final SimpleTypeConverter simpleTypeConverter;
|
||||
|
||||
private JpqQueryRSQLVisitor(final Root<T> root, final CriteriaBuilder cb, final Class<A> enumType) {
|
||||
private JpqQueryRSQLVisitor(final Root<T> root, final CriteriaBuilder cb, final Class<A> enumType,
|
||||
VirtualPropertyReplacer virtualPropertyReplacer) {
|
||||
this.root = root;
|
||||
this.cb = cb;
|
||||
this.enumType = enumType;
|
||||
this.virtualPropertyReplacer = virtualPropertyReplacer;
|
||||
simpleTypeConverter = new SimpleTypeConverter();
|
||||
}
|
||||
|
||||
@@ -199,7 +218,7 @@ public final class RSQLUtility {
|
||||
return toSingleList(cb.conjunction());
|
||||
}
|
||||
|
||||
private List<Predicate> toSingleList(final Predicate predicate) {
|
||||
private static List<Predicate> toSingleList(final Predicate predicate) {
|
||||
return Collections.singletonList(predicate);
|
||||
}
|
||||
|
||||
@@ -348,13 +367,10 @@ public final class RSQLUtility {
|
||||
private Object convertValueIfNecessary(final ComparisonNode node, final A fieldName, final String value,
|
||||
final Path<Object> fieldPath) {
|
||||
// in case the value of an rsql query e.g. type==application is an
|
||||
// enum we need to
|
||||
// handle it separately because JPA needs the correct java-type to
|
||||
// build an
|
||||
// expression. So String and numeric values JPA can do it by it's
|
||||
// own but not for
|
||||
// classes like enums. So we need to transform the given value
|
||||
// string into the enum
|
||||
// enum we need to handle it separately because JPA needs the
|
||||
// correct java-type to build an expression. So String and numeric
|
||||
// values JPA can do it by it's own but not for classes like enums.
|
||||
// So we need to transform the given value string into the enum
|
||||
// class.
|
||||
final Class<? extends Object> javaType = fieldPath.getJavaType();
|
||||
if (javaType != null && javaType.isEnum()) {
|
||||
@@ -399,15 +415,14 @@ public final class RSQLUtility {
|
||||
// Exception squid:S2095 - see
|
||||
// https://jira.sonarsource.com/browse/SONARJAVA-1478
|
||||
@SuppressWarnings({ "rawtypes", "unchecked", "squid:S2095" })
|
||||
private Object transformEnumValue(final ComparisonNode node, final String value,
|
||||
private static Object transformEnumValue(final ComparisonNode node, final String value,
|
||||
final Class<? extends Object> javaType) {
|
||||
final Class<? extends Enum> tmpEnumType = (Class<? extends Enum>) javaType;
|
||||
try {
|
||||
return Enum.valueOf(tmpEnumType, value.toUpperCase());
|
||||
} catch (final IllegalArgumentException e) {
|
||||
// we could not transform the given string value into the enum
|
||||
// type, so ignore
|
||||
// it and return null and do not filter
|
||||
// type, so ignore it and return null and do not filter
|
||||
LOGGER.info("given value {} cannot be transformed into the correct enum type {}", value.toUpperCase(),
|
||||
javaType);
|
||||
LOGGER.debug("value cannot be transformed to an enum", e);
|
||||
@@ -422,10 +437,16 @@ public final class RSQLUtility {
|
||||
private List<Predicate> mapToPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
||||
final List<String> values, final List<Object> transformedValues, final A enumField) {
|
||||
// only 'equal' and 'notEqual' can handle transformed value like
|
||||
// enums. The JPA API
|
||||
// cannot handle object types for greaterThan etc methods.
|
||||
// enums. The JPA API cannot handle object types for greaterThan etc
|
||||
// methods.
|
||||
final Object transformedValue = transformedValues.get(0);
|
||||
final String value = values.get(0);
|
||||
|
||||
String value = values.get(0);
|
||||
// if lookup is available, replace macros ...
|
||||
if (virtualPropertyReplacer != null) {
|
||||
value = virtualPropertyReplacer.replace(value);
|
||||
}
|
||||
|
||||
final List<Predicate> singleList = new ArrayList<>();
|
||||
|
||||
final Predicate mapPredicate = mapToMapPredicate(node, fieldPath, enumField);
|
||||
@@ -541,12 +562,12 @@ public final class RSQLUtility {
|
||||
return cb.notEqual(fieldPath, transformedValue);
|
||||
}
|
||||
|
||||
private String escapeValueToSQL(final String transformedValue) {
|
||||
private static String escapeValueToSQL(final String transformedValue) {
|
||||
return transformedValue.replace("%", "\\%").replace(LIKE_WILDCARD, '%');
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <Y> Path<Y> pathOfString(final Path<?> path) {
|
||||
private static <Y> Path<Y> pathOfString(final Path<?> path) {
|
||||
return (Path<Y>) path;
|
||||
}
|
||||
|
||||
@@ -565,4 +586,5 @@ public final class RSQLUtility {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ public final class TargetSpecifications {
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by "equal to given
|
||||
* {@link TargetUpdateStatus}".
|
||||
*
|
||||
*
|
||||
* @param updateStatus
|
||||
* to be filtered on
|
||||
* @param fetch
|
||||
@@ -113,10 +113,34 @@ public final class TargetSpecifications {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s that are overdue. A
|
||||
* target is overdue if it did not respond during the configured
|
||||
* intervals:<br>
|
||||
* <em>poll_itvl + overdue_itvl</em>
|
||||
*
|
||||
* @param overdueTimestamp
|
||||
* the calculated timestamp to compare with the last respond of a
|
||||
* target (lastTargetQuery).<br>
|
||||
* The <code>overdueTimestamp</code> has to be calculated with
|
||||
* the following expression:<br>
|
||||
* <em>overdueTimestamp = nowTimestamp - poll_itvl -
|
||||
* overdue_itvl</em>
|
||||
*
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> isOverdue(final long overdueTimestamp) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final Join<JpaTarget, JpaTargetInfo> targetInfoJoin = targetRoot.join(JpaTarget_.targetInfo);
|
||||
return cb.lessThanOrEqualTo(
|
||||
targetInfoJoin.get(JpaTargetInfo_.lastTargetQuery), overdueTimestamp);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by
|
||||
* "like controllerId or like description or like ip address".
|
||||
*
|
||||
*
|
||||
* @param searchText
|
||||
* to be filtered on
|
||||
* @return the {@link Target} {@link Specification}
|
||||
@@ -132,7 +156,7 @@ public final class TargetSpecifications {
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by
|
||||
* "like controllerId".
|
||||
*
|
||||
*
|
||||
* @param distributionId
|
||||
* to be filtered on
|
||||
* @return the {@link Target} {@link Specification}
|
||||
@@ -169,7 +193,7 @@ public final class TargetSpecifications {
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by
|
||||
* "has no tag names"or "has at least on of the given tag names".
|
||||
*
|
||||
*
|
||||
* @param tagNames
|
||||
* to be filtered on
|
||||
* @param selectTargetWithNoTag
|
||||
@@ -202,7 +226,7 @@ public final class TargetSpecifications {
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by assigned
|
||||
* distribution set.
|
||||
*
|
||||
*
|
||||
* @param distributionSetId
|
||||
* the ID of the distribution set which must be assigned
|
||||
* @return the {@link Target} {@link Specification}
|
||||
@@ -234,7 +258,7 @@ public final class TargetSpecifications {
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by assigned
|
||||
* distribution set.
|
||||
*
|
||||
*
|
||||
* @param distributionSetId
|
||||
* the ID of the distribution set which must be assigned
|
||||
* @return the {@link Target} {@link Specification}
|
||||
|
||||
@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -17,6 +18,7 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.FilterParams;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
@@ -53,26 +55,42 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
final DistributionSet installedSet = testdataFactory.createDistributionSet("another");
|
||||
|
||||
final Long lastTargetQueryNotOverdue = Instant.now().toEpochMilli();
|
||||
final Long lastTargetQueryAlwaysOverdue = 0L;
|
||||
final Long lastTargetNull = null;
|
||||
|
||||
final String targetDsAIdPref = "targ-A";
|
||||
List<Target> targAs = targetManagement.createTargets(
|
||||
testdataFactory.generateTargets(100, targetDsAIdPref, targetDsAIdPref.concat(" description")));
|
||||
List<Target> targAs = new ArrayList<Target>();
|
||||
for (Target t : testdataFactory.generateTargets(100, targetDsAIdPref, targetDsAIdPref.concat(" description"))) {
|
||||
targAs.add(targetManagement.createTarget(t, TargetUpdateStatus.UNKNOWN, lastTargetQueryNotOverdue,
|
||||
t.getTargetInfo().getAddress()));
|
||||
}
|
||||
targAs = targetManagement.toggleTagAssignment(targAs, targTagX).getAssignedEntity();
|
||||
|
||||
final String targetDsBIdPref = "targ-B";
|
||||
List<Target> targBs = targetManagement.createTargets(
|
||||
testdataFactory.generateTargets(100, targetDsBIdPref, targetDsBIdPref.concat(" description")));
|
||||
List<Target> targBs = new ArrayList<Target>();
|
||||
for (Target t : testdataFactory.generateTargets(100, targetDsBIdPref, targetDsBIdPref.concat(" description"))) {
|
||||
targBs.add(targetManagement.createTarget(t, TargetUpdateStatus.UNKNOWN, lastTargetQueryAlwaysOverdue,
|
||||
t.getTargetInfo().getAddress()));
|
||||
}
|
||||
targBs = targetManagement.toggleTagAssignment(targBs, targTagY).getAssignedEntity();
|
||||
targBs = targetManagement.toggleTagAssignment(targBs, targTagW).getAssignedEntity();
|
||||
|
||||
final String targetDsCIdPref = "targ-C";
|
||||
List<Target> targCs = targetManagement.createTargets(
|
||||
testdataFactory.generateTargets(100, targetDsCIdPref, targetDsCIdPref.concat(" description")));
|
||||
List<Target> targCs = new ArrayList<Target>();
|
||||
for (Target t : testdataFactory.generateTargets(100, targetDsCIdPref, targetDsCIdPref.concat(" description"))) {
|
||||
targCs.add(targetManagement.createTarget(t, TargetUpdateStatus.UNKNOWN, lastTargetQueryAlwaysOverdue,
|
||||
t.getTargetInfo().getAddress()));
|
||||
}
|
||||
targCs = targetManagement.toggleTagAssignment(targCs, targTagZ).getAssignedEntity();
|
||||
targCs = targetManagement.toggleTagAssignment(targCs, targTagW).getAssignedEntity();
|
||||
|
||||
final String targetDsDIdPref = "targ-D";
|
||||
final List<Target> targDs = targetManagement.createTargets(
|
||||
testdataFactory.generateTargets(100, targetDsDIdPref, targetDsDIdPref.concat(" description")));
|
||||
List<Target> targDs = new ArrayList<Target>();
|
||||
for (Target t : testdataFactory.generateTargets(100, targetDsDIdPref, targetDsDIdPref.concat(" description"))) {
|
||||
targDs.add(targetManagement.createTarget(t, TargetUpdateStatus.UNKNOWN, lastTargetNull,
|
||||
t.getTargetInfo().getAddress()));
|
||||
}
|
||||
|
||||
final String assignedC = targCs.iterator().next().getControllerId();
|
||||
deploymentManagement.assignDistributionSet(setA.getId(), assignedC);
|
||||
@@ -148,6 +166,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
verifyThat200targetsWithGivenTagAreInStatusPendingorUnknown(targTagW, both, concat(targBs, targCs));
|
||||
verfiyThat1TargetAIsInStatusPendingAndHasDSInstalled(installedSet, pending,
|
||||
targetManagement.findTargetByControllerID(installedC));
|
||||
|
||||
expected = concat(targBs, targCs);
|
||||
expected.removeAll(targetManagement.findTargetByControllerID(Lists.newArrayList(assignedB, assignedC)));
|
||||
verifyThat198TargetsAreInStatusUnknownAndOverdue(unknown, expected);
|
||||
}
|
||||
|
||||
@Step
|
||||
@@ -157,10 +179,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final String query = "updatestatus==pending and installedds.name==" + installedSet.getName();
|
||||
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, pending, null, installedSet.getId(), Boolean.FALSE, new String[0])
|
||||
.findTargetByFilters(pageReq, pending, null, null, installedSet.getId(), Boolean.FALSE, new String[0])
|
||||
.getContent()).as("has number of elements").hasSize(1)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null,
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null,
|
||||
installedSet.getId(), Boolean.FALSE, new String[0])))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
@@ -168,7 +190,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, installedSet.getId(),
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, installedSet.getId(),
|
||||
Boolean.FALSE, new String[0])).as("has number of elements").hasSize(1)
|
||||
.as("and contains the following elements").containsExactly(expectedIdName)
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
@@ -183,10 +205,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
final String query = "(updatestatus==pending or updatestatus==unknown) and tag==" + targTagW.getName();
|
||||
|
||||
assertThat(targetManagement.findTargetByFilters(pageReq, both, null, null, Boolean.FALSE, targTagW.getName())
|
||||
.getContent()).as("has number of elements").hasSize(200)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(both, null, null,
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, both, null, null, null, Boolean.FALSE, targTagW.getName()).getContent())
|
||||
.as("has number of elements").hasSize(200).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(both, null, null, null,
|
||||
Boolean.FALSE, targTagW.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
@@ -194,7 +216,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, both, null, null, Boolean.FALSE,
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, both, null, null, null, Boolean.FALSE,
|
||||
targTagW.getName())).as("has number of elements").hasSize(200).as("and contains the following elements")
|
||||
.containsAll(expectedIdNames).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
@@ -217,10 +239,11 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final List<TargetIdName> expectedIdNames = convertToIdNames(expected);
|
||||
final String query = "updatestatus==pending and tag==" + targTagW.getName();
|
||||
|
||||
assertThat(targetManagement.findTargetByFilters(pageReq, pending, null, null, Boolean.FALSE, targTagW.getName())
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, pending, null, null, null, Boolean.FALSE, targTagW.getName())
|
||||
.getContent()).as("has number of elements").hasSize(2)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null,
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null, null,
|
||||
Boolean.FALSE, targTagW.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
@@ -228,7 +251,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, Boolean.FALSE,
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, null, Boolean.FALSE,
|
||||
targTagW.getName())).as("has number of elements").hasSize(2).as("and contains the following elements")
|
||||
.containsAll(expectedIdNames).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
@@ -243,18 +266,18 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
+ setA.getName() + ") and tag==" + targTagW.getName();
|
||||
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, pending, null, setA.getId(), Boolean.FALSE, targTagW.getName())
|
||||
.findTargetByFilters(pageReq, pending, null, null, setA.getId(), Boolean.FALSE, targTagW.getName())
|
||||
.getContent()).as("has number of elements").hasSize(2)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, setA.getId(),
|
||||
Boolean.FALSE, targTagW.getName())))
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null,
|
||||
setA.getId(), Boolean.FALSE, targTagW.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findTargetsAll(query, pageReq).getContent())
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, Boolean.FALSE,
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, null, Boolean.FALSE,
|
||||
targTagW.getName())).as("has number of elements").hasSize(2).as("and contains the following elements")
|
||||
.containsAll(expectedIdNames).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
@@ -268,11 +291,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
|
||||
+ setA.getName() + ") and (name==*targ-B* or description==*targ-B*) and tag==" + targTagW.getName();
|
||||
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, pending, "%targ-B%", setA.getId(), Boolean.FALSE, targTagW.getName())
|
||||
.getContent()).as("has number of elements").hasSize(1)
|
||||
assertThat(targetManagement.findTargetByFilters(pageReq, pending, null, "%targ-B%", setA.getId(), Boolean.FALSE,
|
||||
targTagW.getName()).getContent()).as("has number of elements").hasSize(1)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, "%targ-B%",
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, "%targ-B%",
|
||||
setA.getId(), Boolean.FALSE, targTagW.getName())))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
@@ -280,11 +302,11 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, "%targ-B%", setA.getId(), Boolean.FALSE,
|
||||
targTagW.getName())).as("has number of elements").hasSize(1).as("and contains the following elements")
|
||||
.containsExactly(expectedIdName).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
new JpaTargetFilterQuery("test", query)));
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, "%targ-B%", setA.getId(),
|
||||
Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(1)
|
||||
.as("and contains the following elements").containsExactly(expectedIdName)
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query)));
|
||||
}
|
||||
|
||||
@Step
|
||||
@@ -295,10 +317,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
+ setA.getName() + ") and (name==*targ-A* or description==*targ-A*)";
|
||||
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, pending, "%targ-A%", setA.getId(), Boolean.FALSE, new String[0])
|
||||
.findTargetByFilters(pageReq, pending, null, "%targ-A%", setA.getId(), Boolean.FALSE, new String[0])
|
||||
.getContent()).as("has number of elements").hasSize(1)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, "%targ-A%",
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, "%targ-A%",
|
||||
setA.getId(), Boolean.FALSE, new String[0])))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
@@ -306,11 +328,11 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, "%targ-A%", setA.getId(), Boolean.FALSE,
|
||||
new String[0])).as("has number of elements").hasSize(1).as("and contains the following elements")
|
||||
.containsExactly(expectedIdName).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
new JpaTargetFilterQuery("test", query)));
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, "%targ-A%", setA.getId(),
|
||||
Boolean.FALSE, new String[0])).as("has number of elements").hasSize(1)
|
||||
.as("and contains the following elements").containsExactly(expectedIdName)
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query)));
|
||||
}
|
||||
|
||||
@Step
|
||||
@@ -321,17 +343,17 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
+ setA.getName() + ")";
|
||||
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, pending, null, setA.getId(), Boolean.FALSE, new String[0]).getContent())
|
||||
.as("has number of elements").hasSize(3).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, setA.getId(),
|
||||
Boolean.FALSE, new String[0])))
|
||||
.findTargetByFilters(pageReq, pending, null, null, setA.getId(), Boolean.FALSE, new String[0])
|
||||
.getContent()).as("has number of elements").hasSize(3).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null,
|
||||
setA.getId(), Boolean.FALSE, new String[0])))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findTargetsAll(query, pageReq).getContent())
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, setA.getId(), Boolean.FALSE,
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, setA.getId(), Boolean.FALSE,
|
||||
new String[0])).as("has number of elements").hasSize(3).as("and contains the following elements")
|
||||
.containsAll(expectedIdNames).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
@@ -344,10 +366,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final List<TargetIdName> expectedIdNames = convertToIdNames(expected);
|
||||
final String query = "updatestatus==pending";
|
||||
|
||||
assertThat(targetManagement.findTargetByFilters(pageReq, pending, null, null, Boolean.FALSE, new String[0])
|
||||
.getContent()).as("has number of elements").hasSize(3)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null,
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, pending, null, null, null, Boolean.FALSE, new String[0]).getContent())
|
||||
.as("has number of elements").hasSize(3).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null, null,
|
||||
Boolean.FALSE, new String[0])))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
@@ -355,9 +377,8 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(
|
||||
targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, Boolean.FALSE, new String[0]))
|
||||
.as("has number of elements").hasSize(3).as("and contains the following elements")
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, null, Boolean.FALSE,
|
||||
new String[0])).as("has number of elements").hasSize(3).as("and contains the following elements")
|
||||
.containsAll(expectedIdNames).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
new JpaTargetFilterQuery("test", query)));
|
||||
@@ -371,18 +392,18 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
+ targTagW.getName();
|
||||
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, unknown, "%targ-B%", null, Boolean.FALSE, targTagW.getName())
|
||||
.findTargetByFilters(pageReq, unknown, null, "%targ-B%", null, Boolean.FALSE, targTagW.getName())
|
||||
.getContent()).as("has number of elements").hasSize(99)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, "%targ-B%", null,
|
||||
Boolean.FALSE, targTagW.getName())))
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, "%targ-B%",
|
||||
null, Boolean.FALSE, targTagW.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findTargetsAll(query, pageReq).getContent())
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, "%targ-B%", null, Boolean.FALSE,
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, "%targ-B%", null, Boolean.FALSE,
|
||||
targTagW.getName())).as("has number of elements").hasSize(99).as("and contains the following elements")
|
||||
.containsAll(expectedIdNames).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
@@ -396,17 +417,17 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final String query = "updatestatus==unknown and (name==*targ-A* or description==*targ-A*)";
|
||||
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, unknown, "%targ-A%", null, Boolean.FALSE, new String[0]).getContent())
|
||||
.as("has number of elements").hasSize(99).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, "%targ-A%", null,
|
||||
Boolean.FALSE, new String[0])))
|
||||
.findTargetByFilters(pageReq, unknown, null, "%targ-A%", null, Boolean.FALSE, new String[0])
|
||||
.getContent()).as("has number of elements").hasSize(99)
|
||||
.as("that number is also returned by count query").hasSize(Ints.saturatedCast(targetManagement
|
||||
.countTargetByFilters(unknown, null, "%targ-A%", null, Boolean.FALSE, new String[0])))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findTargetsAll(query, pageReq).getContent())
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, "%targ-A%", null, Boolean.FALSE,
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, "%targ-A%", null, Boolean.FALSE,
|
||||
new String[0])).as("has number of elements").hasSize(99).as("and contains the following elements")
|
||||
.containsAll(expectedIdNames).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
@@ -420,16 +441,16 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
+ setA.getName() + ")";
|
||||
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, unknown, null, setA.getId(), Boolean.FALSE, new String[0]).getContent())
|
||||
.as("has number of elements").hasSize(0).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, setA.getId(),
|
||||
Boolean.FALSE, new String[0])))
|
||||
.findTargetByFilters(pageReq, unknown, null, null, setA.getId(), Boolean.FALSE, new String[0])
|
||||
.getContent()).as("has number of elements").hasSize(0).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, null,
|
||||
setA.getId(), Boolean.FALSE, new String[0])))
|
||||
.as("and filter query returns the same result")
|
||||
.hasSize(targetManagement.findTargetsAll(query, pageReq).getContent().size())
|
||||
.as("and NAMED filter query returns the same result").hasSize(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent().size());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, setA.getId(), Boolean.FALSE,
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, null, setA.getId(), Boolean.FALSE,
|
||||
new String[0])).as("has number of elements").hasSize(0)
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query)));
|
||||
@@ -442,10 +463,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final String query = "updatestatus==unknown and (tag==" + targTagY.getName() + " or tag==" + targTagW.getName()
|
||||
+ ")";
|
||||
|
||||
assertThat(targetManagement.findTargetByFilters(pageReq, unknown, null, null, Boolean.FALSE, targTagY.getName(),
|
||||
targTagW.getName()).getContent()).as("has number of elements").hasSize(198)
|
||||
assertThat(targetManagement.findTargetByFilters(pageReq, unknown, null, null, null, Boolean.FALSE,
|
||||
targTagY.getName(), targTagW.getName()).getContent()).as("has number of elements").hasSize(198)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, null,
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, null, null,
|
||||
Boolean.FALSE, targTagY.getName(), targTagW.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
@@ -453,7 +474,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, null, Boolean.FALSE,
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, null, null, Boolean.FALSE,
|
||||
targTagY.getName(), targTagW.getName())).as("has number of elements").hasSize(198)
|
||||
.as("and contains the following elements").containsAll(expectedIdNames)
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
@@ -466,10 +487,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final List<TargetIdName> expectedIdNames = convertToIdNames(expected);
|
||||
final String query = "updatestatus==unknown";
|
||||
|
||||
assertThat(targetManagement.findTargetByFilters(pageReq, unknown, null, null, Boolean.FALSE, new String[0])
|
||||
.getContent()).as("has number of elements").hasSize(397)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, null,
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, unknown, null, null, null, Boolean.FALSE, new String[0]).getContent())
|
||||
.as("has number of elements").hasSize(397).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, null, null,
|
||||
Boolean.FALSE, new String[0])))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
@@ -477,9 +498,34 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(
|
||||
targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, null, Boolean.FALSE, new String[0]))
|
||||
.as("has number of elements").hasSize(397).as("and contains the following elements")
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, null, null, Boolean.FALSE,
|
||||
new String[0])).as("has number of elements").hasSize(397).as("and contains the following elements")
|
||||
.containsAll(expectedIdNames).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
new JpaTargetFilterQuery("test", query)));
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat198TargetsAreInStatusUnknownAndOverdue(final List<TargetUpdateStatus> unknown,
|
||||
final List<Target> expected) {
|
||||
final List<TargetIdName> expectedIdNames = convertToIdNames(expected);
|
||||
// be careful: simple filters are concatenated using AND-gating
|
||||
final String query = "lastcontrollerrequestat=le=${overdue_ts};updatestatus==UNKNOWN";
|
||||
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, unknown, Boolean.TRUE, null, null, Boolean.FALSE, new String[0])
|
||||
.getContent()).as("has number of elements").hasSize(198)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, Boolean.TRUE, null,
|
||||
null, Boolean.FALSE, new String[0])))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findTargetsAll(query, pageReq).getContent())
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, Boolean.TRUE, null, null, Boolean.FALSE,
|
||||
new String[0])).as("has number of elements").hasSize(198).as("and contains the following elements")
|
||||
.containsAll(expectedIdNames).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
new JpaTargetFilterQuery("test", query)));
|
||||
@@ -492,10 +538,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
+ " or installedds.name==" + setA.getName() + ")";
|
||||
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, null, "%targ-A%", setA.getId(), Boolean.FALSE, new String[0])
|
||||
.findTargetByFilters(pageReq, null, null, "%targ-A%", setA.getId(), Boolean.FALSE, new String[0])
|
||||
.getContent()).as("has number of elements").hasSize(1)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, "%targ-A%",
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, "%targ-A%",
|
||||
setA.getId(), Boolean.FALSE, new String[0])))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
@@ -503,11 +549,11 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-A%", setA.getId(), Boolean.FALSE,
|
||||
new String[0])).as("has number of elements").hasSize(1).as("and contains the following elements")
|
||||
.containsExactly(expectedIdName).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
new JpaTargetFilterQuery("test", query)));
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, "%targ-A%", setA.getId(),
|
||||
Boolean.FALSE, new String[0])).as("has number of elements").hasSize(1)
|
||||
.as("and contains the following elements").containsExactly(expectedIdName)
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query)));
|
||||
}
|
||||
|
||||
@Step
|
||||
@@ -515,18 +561,19 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final List<TargetIdName> expectedIdNames = convertToIdNames(expected);
|
||||
final String query = "assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName();
|
||||
|
||||
assertThat(targetManagement.findTargetByFilters(pageReq, null, null, setA.getId(), Boolean.FALSE, new String[0])
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, null, null, null, setA.getId(), Boolean.FALSE, new String[0])
|
||||
.getContent()).as("has number of elements").hasSize(3)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, setA.getId(),
|
||||
Boolean.FALSE, new String[0])))
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, null,
|
||||
setA.getId(), Boolean.FALSE, new String[0])))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findTargetsAll(query, pageReq).getContent())
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, setA.getId(), Boolean.FALSE,
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, null, setA.getId(), Boolean.FALSE,
|
||||
new String[0])).as("has number of elements").hasSize(3).as("and contains the following elements")
|
||||
.containsAll(expectedIdNames).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
@@ -538,18 +585,18 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final String query = "(name==*targ-C* or description==*targ-C*) and tag==" + targTagX.getName()
|
||||
+ " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")";
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagX.getName())
|
||||
.findTargetByFilters(pageReq, null, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagX.getName())
|
||||
.getContent()).as("has number of elements").hasSize(0)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, "%targ-C%",
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, "%targ-C%",
|
||||
setA.getId(), Boolean.FALSE, targTagX.getName())))
|
||||
.as("and filter query returns the same result")
|
||||
.hasSize(targetManagement.findTargetsAll(query, pageReq).getContent().size())
|
||||
.as("and NAMED filter query returns the same result").hasSize(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent().size());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-C%", setA.getId(), Boolean.FALSE,
|
||||
targTagX.getName())).as("has number of elements").hasSize(0)
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, "%targ-C%", setA.getId(),
|
||||
Boolean.FALSE, targTagX.getName())).as("has number of elements").hasSize(0)
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query)));
|
||||
}
|
||||
@@ -559,18 +606,18 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final String query = "(name==*targ-A* or description==*targ-A*) and tag==" + targTagW.getName()
|
||||
+ " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")";
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, null, "%targ-A%", setA.getId(), Boolean.FALSE, targTagW.getName())
|
||||
.findTargetByFilters(pageReq, null, null, "%targ-A%", setA.getId(), Boolean.FALSE, targTagW.getName())
|
||||
.getContent()).as("has number of elements").hasSize(0)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, "%targ-A%",
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, "%targ-A%",
|
||||
setA.getId(), Boolean.FALSE, targTagW.getName())))
|
||||
.as("and filter query returns the same result")
|
||||
.hasSize(targetManagement.findTargetsAll(query, pageReq).getContent().size())
|
||||
.as("and NAMED filter query returns the same result").hasSize(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent().size());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-A%", setA.getId(), Boolean.FALSE,
|
||||
targTagW.getName())).as("has number of elements").hasSize(0)
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, "%targ-A%", setA.getId(),
|
||||
Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(0)
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query)));
|
||||
}
|
||||
@@ -582,10 +629,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final String query = "(name==*targ-c* or description==*targ-C*) and tag==" + targTagW.getName()
|
||||
+ " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")";
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagW.getName())
|
||||
.findTargetByFilters(pageReq, null, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagW.getName())
|
||||
.getContent()).as("has number of elements").hasSize(1)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, "%targ-C%",
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, "%targ-C%",
|
||||
setA.getId(), Boolean.FALSE, targTagW.getName())))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
@@ -593,11 +640,11 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-C%", setA.getId(), Boolean.FALSE,
|
||||
targTagW.getName())).as("has number of elements").hasSize(1).as("and contains the following elements")
|
||||
.containsExactly(expectedIdName).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
new JpaTargetFilterQuery("test", query)));
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, "%targ-C%", setA.getId(),
|
||||
Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(1)
|
||||
.as("and contains the following elements").containsExactly(expectedIdName)
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query)));
|
||||
}
|
||||
|
||||
@Step
|
||||
@@ -606,10 +653,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final List<TargetIdName> expectedIdNames = convertToIdNames(expected);
|
||||
final String query = "(name==*targ-B* or description==*targ-B*) and (tag==" + targTagY.getName() + " or tag=="
|
||||
+ targTagW.getName() + ")";
|
||||
assertThat(targetManagement.findTargetByFilters(pageReq, null, "%targ-B%", null, Boolean.FALSE,
|
||||
assertThat(targetManagement.findTargetByFilters(pageReq, null, null, "%targ-B%", null, Boolean.FALSE,
|
||||
targTagY.getName(), targTagW.getName()).getContent()).as("has number of elements").hasSize(100)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, "%targ-B%", null,
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, "%targ-B%", null,
|
||||
Boolean.FALSE, targTagY.getName(), targTagW.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
@@ -617,7 +664,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-B%", null, Boolean.FALSE,
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, "%targ-B%", null, Boolean.FALSE,
|
||||
targTagY.getName(), targTagW.getName())).as("has number of elements").hasSize(100)
|
||||
.as("and contains the following elements").containsAll(expectedIdNames)
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
@@ -636,10 +683,11 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
private void verifyThat200TargetsHaveTagD(final TargetTag targTagD, final List<Target> expected) {
|
||||
final List<TargetIdName> expectedIdNames = convertToIdNames(expected);
|
||||
final String query = "tag==" + targTagD.getName();
|
||||
assertThat(targetManagement.findTargetByFilters(pageReq, null, null, null, Boolean.FALSE, targTagD.getName())
|
||||
.getContent()).as("Expected number of results is").hasSize(200)
|
||||
assertThat(targetManagement
|
||||
.findTargetByFilters(pageReq, null, null, null, null, Boolean.FALSE, targTagD.getName()).getContent())
|
||||
.as("Expected number of results is").hasSize(200)
|
||||
.as("and is expected number of results is equal to ")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, null,
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, null, null,
|
||||
Boolean.FALSE, targTagD.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
@@ -647,7 +695,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.as("and NAMED filter query returns the same result").containsAll(targetManagement
|
||||
.findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent());
|
||||
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, null, Boolean.FALSE,
|
||||
assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, null, null, Boolean.FALSE,
|
||||
targTagD.getName())).as("has number of elements").hasSize(200).as("and contains the following elements")
|
||||
.containsAll(expectedIdNames).as("and NAMED filter query returns the same result")
|
||||
.containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq,
|
||||
@@ -657,12 +705,13 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Step
|
||||
private void verifyThatRepositoryContains400Targets() {
|
||||
assertThat(targetManagement.findTargetByFilters(pageReq, null, null, null, null, new String[0]).getContent())
|
||||
.as("Overall we expect that many targets in the repository").hasSize(400)
|
||||
.as("which is also reflected by repository count")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetsAll()))
|
||||
.as("which is also reflected by call without specification")
|
||||
.containsAll(targetManagement.findTargetsAll(pageReq).getContent());
|
||||
assertThat(
|
||||
targetManagement.findTargetByFilters(pageReq, null, null, null, null, null, new String[0]).getContent())
|
||||
.as("Overall we expect that many targets in the repository").hasSize(400)
|
||||
.as("which is also reflected by repository count")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countTargetsAll()))
|
||||
.as("which is also reflected by call without specification")
|
||||
.containsAll(targetManagement.findTargetsAll(pageReq).getContent());
|
||||
|
||||
}
|
||||
|
||||
@@ -685,7 +734,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
targInstalled = sendUpdateActionStatusToTargets(ds, targInstalled, Status.FINISHED, "installed");
|
||||
|
||||
final Slice<Target> result = targetManagement.findTargetsAllOrderByLinkedDistributionSet(pageReq, ds.getId(),
|
||||
null, null, null, Boolean.FALSE, new String[0]);
|
||||
new FilterParams(null, null, null, null, Boolean.FALSE, new String[0]));
|
||||
|
||||
final Comparator<TenantAwareBaseEntity> byId = (e1, e2) -> Long.compare(e2.getId(), e1.getId());
|
||||
|
||||
@@ -702,6 +751,64 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests the correct order of targets with applied overdue filter based on selected distribution set. The system expects to have an order based on installed, assigned DS.")
|
||||
public void targetSearchWithOverdueFilterAndOrderByDistributionSet() {
|
||||
|
||||
final Long lastTargetQueryAlwaysOverdue = 0L;
|
||||
final Long lastTargetQueryNotOverdue = Instant.now().toEpochMilli();
|
||||
final Long lastTargetNull = null;
|
||||
|
||||
final Long[] overdueMix = { lastTargetQueryAlwaysOverdue, lastTargetQueryNotOverdue,
|
||||
lastTargetQueryAlwaysOverdue, lastTargetNull, lastTargetQueryAlwaysOverdue };
|
||||
|
||||
List<Target> notAssignedToBeCreated = testdataFactory.generateTargets(overdueMix.length, "not",
|
||||
"first description");
|
||||
List<Target> targAssignedToBeCreated = testdataFactory.generateTargets(overdueMix.length, "assigned",
|
||||
"first description");
|
||||
List<Target> targInstalledToBeCreated = testdataFactory.generateTargets(overdueMix.length, "installed",
|
||||
"first description");
|
||||
|
||||
List<Target> notAssigned = new ArrayList<>();
|
||||
List<Target> targAssigned = new ArrayList<>();
|
||||
List<Target> targInstalled = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < overdueMix.length; i++) {
|
||||
notAssigned.add(targetManagement.createTarget(notAssignedToBeCreated.get(i), TargetUpdateStatus.UNKNOWN,
|
||||
overdueMix[i], notAssignedToBeCreated.get(i).getTargetInfo().getAddress()));
|
||||
targAssigned.add(targetManagement.createTarget(targAssignedToBeCreated.get(i), TargetUpdateStatus.UNKNOWN,
|
||||
overdueMix[i], targAssignedToBeCreated.get(i).getTargetInfo().getAddress()));
|
||||
targInstalled.add(targetManagement.createTarget(targInstalledToBeCreated.get(i), TargetUpdateStatus.UNKNOWN,
|
||||
overdueMix[i], targInstalledToBeCreated.get(i).getTargetInfo().getAddress()));
|
||||
}
|
||||
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("a");
|
||||
|
||||
targAssigned = deploymentManagement.assignDistributionSet(ds, targAssigned).getAssignedEntity();
|
||||
targInstalled = deploymentManagement.assignDistributionSet(ds, targInstalled).getAssignedEntity();
|
||||
targInstalled = sendUpdateActionStatusToTargets(ds, targInstalled, Status.FINISHED, "installed");
|
||||
|
||||
final Slice<Target> result = targetManagement.findTargetsAllOrderByLinkedDistributionSet(pageReq, ds.getId(),
|
||||
new FilterParams(null, null, Boolean.TRUE, null, Boolean.FALSE, new String[0]));
|
||||
|
||||
final Comparator<TenantAwareBaseEntity> byId = (e1, e2) -> Long.compare(e2.getId(), e1.getId());
|
||||
|
||||
assertThat(result.getNumberOfElements()).isEqualTo(9);
|
||||
final List<Target> expected = new ArrayList<>();
|
||||
expected.addAll(targInstalled.stream().sorted(byId)
|
||||
.filter(item -> lastTargetQueryAlwaysOverdue.equals(item.getTargetInfo().getLastTargetQuery()))
|
||||
.collect(Collectors.toList()));
|
||||
expected.addAll(targAssigned.stream().sorted(byId)
|
||||
.filter(item -> lastTargetQueryAlwaysOverdue.equals(item.getTargetInfo().getLastTargetQuery()))
|
||||
.collect(Collectors.toList()));
|
||||
expected.addAll(notAssigned.stream().sorted(byId)
|
||||
.filter(item -> lastTargetQueryAlwaysOverdue.equals(item.getTargetInfo().getLastTargetQuery()))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
assertThat(result.getContent()).containsExactly(expected.toArray(new Target[0]));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verfies that targets with given assigned DS are returned from repository.")
|
||||
public void findTargetByAssignedDistributionSet() {
|
||||
|
||||
@@ -601,7 +601,7 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
targetManagement.toggleTagAssignment(tagABCTargets, tagB);
|
||||
targetManagement.toggleTagAssignment(tagABCTargets, tagC);
|
||||
|
||||
assertThat(targetManagement.countTargetByFilters(null, null, null, Boolean.FALSE, "X"))
|
||||
assertThat(targetManagement.countTargetByFilters(null, null, null, null, Boolean.FALSE, "X"))
|
||||
.as("Target count is wrong").isEqualTo(0);
|
||||
|
||||
// search for targets with tag tagA
|
||||
@@ -631,11 +631,11 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
checkTargetHasNotTags(tagCTargets, tagA, tagB);
|
||||
|
||||
// check again target lists refreshed from DB
|
||||
assertThat(targetManagement.countTargetByFilters(null, null, null, Boolean.FALSE, "A"))
|
||||
assertThat(targetManagement.countTargetByFilters(null, null, null, null, Boolean.FALSE, "A"))
|
||||
.as("Target count is wrong").isEqualTo(targetWithTagA.size());
|
||||
assertThat(targetManagement.countTargetByFilters(null, null, null, Boolean.FALSE, "B"))
|
||||
assertThat(targetManagement.countTargetByFilters(null, null, null, null, Boolean.FALSE, "B"))
|
||||
.as("Target count is wrong").isEqualTo(targetWithTagB.size());
|
||||
assertThat(targetManagement.countTargetByFilters(null, null, null, Boolean.FALSE, "C"))
|
||||
assertThat(targetManagement.countTargetByFilters(null, null, null, null, Boolean.FALSE, "C"))
|
||||
.as("Target count is wrong").isEqualTo(targetWithTagC.size());
|
||||
}
|
||||
|
||||
@@ -752,7 +752,8 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
final String[] tagNames = null;
|
||||
final List<Target> targetsListWithNoTag = targetManagement
|
||||
.findTargetByFilters(new PageRequest(0, 500), null, null, null, Boolean.TRUE, tagNames).getContent();
|
||||
.findTargetByFilters(new PageRequest(0, 500), null, null, null, null, Boolean.TRUE, tagNames)
|
||||
.getContent();
|
||||
|
||||
assertThat(50).as("Total targets").isEqualTo(targetManagement.findAllTargetIds().size());
|
||||
assertThat(25).as("Targets with no tag").isEqualTo(targetsListWithNoTag.size());
|
||||
|
||||
@@ -9,14 +9,9 @@
|
||||
package org.eclipse.hawkbit.repository.jpa.rsql;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.powermock.api.mockito.PowerMockito.mockStatic;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
@@ -30,24 +25,39 @@ import org.eclipse.hawkbit.repository.DistributionSetFields;
|
||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
|
||||
import org.eclipse.hawkbit.repository.TargetFields;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.jpa.TimestampCalculator;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.Spy;
|
||||
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@Features("Component Tests - Repository")
|
||||
@Stories("RSQL search utility")
|
||||
@PrepareForTest(TimestampCalculator.class)
|
||||
// TODO: fully document tests -> @Description for long text and reasonable
|
||||
// method name as short text
|
||||
public class RSQLUtilityTest {
|
||||
|
||||
@Spy
|
||||
private VirtualPropertyResolver macroResolver = new VirtualPropertyResolver();
|
||||
|
||||
@Mock
|
||||
private TenantConfigurationManagement confMgmt;
|
||||
|
||||
@Mock
|
||||
private Root<Object> baseSoftwareModuleRootMock;
|
||||
|
||||
@@ -59,11 +69,16 @@ public class RSQLUtilityTest {
|
||||
@Mock
|
||||
private Attribute attribute;
|
||||
|
||||
private static final TenantConfigurationValue<String> TEST_POLLING_TIME_INTERVAL = TenantConfigurationValue
|
||||
.<String>builder().value("00:05:00").build();
|
||||
private static final TenantConfigurationValue<String> TEST_POLLING_OVERDUE_TIME_INTERVAL = TenantConfigurationValue
|
||||
.<String>builder().value("00:07:37").build();
|
||||
|
||||
@Test
|
||||
public void wrongRsqlSyntaxThrowSyntaxException() {
|
||||
final String wrongRSQL = "name==abc;d";
|
||||
try {
|
||||
RSQLUtility.parse(wrongRSQL, SoftwareModuleFields.class).toPredicate(baseSoftwareModuleRootMock,
|
||||
RSQLUtility.parse(wrongRSQL, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock, criteriaBuilderMock);
|
||||
fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax");
|
||||
} catch (final RSQLParameterSyntaxException e) {
|
||||
@@ -75,7 +90,7 @@ public class RSQLUtilityTest {
|
||||
final String wrongRSQL = "unknownField==abc";
|
||||
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
|
||||
try {
|
||||
RSQLUtility.parse(wrongRSQL, SoftwareModuleFields.class).toPredicate(baseSoftwareModuleRootMock,
|
||||
RSQLUtility.parse(wrongRSQL, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock, criteriaBuilderMock);
|
||||
fail("Missing an expected RSQLParameterUnsupportedFieldException because of unknown RSQL field");
|
||||
} catch (final RSQLParameterUnsupportedFieldException e) {
|
||||
@@ -87,7 +102,8 @@ public class RSQLUtilityTest {
|
||||
public void wrongRsqlMapSyntaxThrowSyntaxException() {
|
||||
String wrongRSQL = TargetFields.ATTRIBUTE + "==abc";
|
||||
try {
|
||||
RSQLUtility.parse(wrongRSQL, TargetFields.class).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock,
|
||||
RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock,
|
||||
criteriaBuilderMock);
|
||||
fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax");
|
||||
} catch (final RSQLParameterUnsupportedFieldException e) {
|
||||
@@ -95,7 +111,8 @@ public class RSQLUtilityTest {
|
||||
|
||||
wrongRSQL = TargetFields.ATTRIBUTE + ".unkwon.wrong==abc";
|
||||
try {
|
||||
RSQLUtility.parse(wrongRSQL, TargetFields.class).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock,
|
||||
RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock,
|
||||
criteriaBuilderMock);
|
||||
fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax");
|
||||
} catch (final RSQLParameterUnsupportedFieldException e) {
|
||||
@@ -103,7 +120,7 @@ public class RSQLUtilityTest {
|
||||
|
||||
wrongRSQL = DistributionSetFields.METADATA + "==abc";
|
||||
try {
|
||||
RSQLUtility.parse(wrongRSQL, DistributionSetFields.class).toPredicate(baseSoftwareModuleRootMock,
|
||||
RSQLUtility.parse(wrongRSQL, DistributionSetFields.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock, criteriaBuilderMock);
|
||||
fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax");
|
||||
} catch (final RSQLParameterUnsupportedFieldException e) {
|
||||
@@ -115,7 +132,8 @@ public class RSQLUtilityTest {
|
||||
public void wrongRsqlSubEntitySyntaxThrowSyntaxException() {
|
||||
String wrongRSQL = TargetFields.ASSIGNEDDS + "==abc";
|
||||
try {
|
||||
RSQLUtility.parse(wrongRSQL, TargetFields.class).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock,
|
||||
RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock,
|
||||
criteriaBuilderMock);
|
||||
fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax");
|
||||
} catch (final RSQLParameterUnsupportedFieldException e) {
|
||||
@@ -123,7 +141,8 @@ public class RSQLUtilityTest {
|
||||
|
||||
wrongRSQL = TargetFields.ASSIGNEDDS + ".unknownField==abc";
|
||||
try {
|
||||
RSQLUtility.parse(wrongRSQL, TargetFields.class).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock,
|
||||
RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock,
|
||||
criteriaBuilderMock);
|
||||
fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax");
|
||||
} catch (final RSQLParameterUnsupportedFieldException e) {
|
||||
@@ -131,7 +150,8 @@ public class RSQLUtilityTest {
|
||||
|
||||
wrongRSQL = TargetFields.ASSIGNEDDS + ".unknownField.ToMuch==abc";
|
||||
try {
|
||||
RSQLUtility.parse(wrongRSQL, TargetFields.class).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock,
|
||||
RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock,
|
||||
criteriaBuilderMock);
|
||||
fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax");
|
||||
} catch (final RSQLParameterUnsupportedFieldException e) {
|
||||
@@ -146,11 +166,11 @@ public class RSQLUtilityTest {
|
||||
when(baseSoftwareModuleRootMock.get("version")).thenReturn(baseSoftwareModuleRootMock);
|
||||
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
|
||||
when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class));
|
||||
when(criteriaBuilderMock.<String> greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
when(criteriaBuilderMock.<String>greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
.thenReturn(mock(Predicate.class));
|
||||
|
||||
// test
|
||||
RSQLUtility.parse(correctRsql, SoftwareModuleFields.class).toPredicate(baseSoftwareModuleRootMock,
|
||||
RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock, criteriaBuilderMock);
|
||||
|
||||
// verfication
|
||||
@@ -164,12 +184,12 @@ public class RSQLUtilityTest {
|
||||
when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock);
|
||||
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
|
||||
when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class));
|
||||
when(criteriaBuilderMock.<String> greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
when(criteriaBuilderMock.<String>greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
.thenReturn(mock(Predicate.class));
|
||||
when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock))))
|
||||
.thenReturn(pathOfString(baseSoftwareModuleRootMock));
|
||||
// test
|
||||
RSQLUtility.parse(correctRsql, SoftwareModuleFields.class).toPredicate(baseSoftwareModuleRootMock,
|
||||
RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock, criteriaBuilderMock);
|
||||
|
||||
// verfication
|
||||
@@ -185,12 +205,12 @@ public class RSQLUtilityTest {
|
||||
when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock);
|
||||
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
|
||||
when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class));
|
||||
when(criteriaBuilderMock.<String> greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
when(criteriaBuilderMock.<String>greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
.thenReturn(mock(Predicate.class));
|
||||
when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock))))
|
||||
.thenReturn(pathOfString(baseSoftwareModuleRootMock));
|
||||
// test
|
||||
RSQLUtility.parse(correctRsql, SoftwareModuleFields.class).toPredicate(baseSoftwareModuleRootMock,
|
||||
RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock, criteriaBuilderMock);
|
||||
|
||||
// verfication
|
||||
@@ -206,10 +226,10 @@ public class RSQLUtilityTest {
|
||||
when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock);
|
||||
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
|
||||
when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class));
|
||||
when(criteriaBuilderMock.<String> greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
when(criteriaBuilderMock.<String>greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
.thenReturn(mock(Predicate.class));
|
||||
// test
|
||||
RSQLUtility.parse(correctRsql, SoftwareModuleFields.class).toPredicate(baseSoftwareModuleRootMock,
|
||||
RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock, criteriaBuilderMock);
|
||||
|
||||
// verfication
|
||||
@@ -226,7 +246,8 @@ public class RSQLUtilityTest {
|
||||
when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class));
|
||||
|
||||
// test
|
||||
RSQLUtility.parse(correctRsql, TestFieldEnum.class).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock,
|
||||
RSQLUtility.parse(correctRsql, TestFieldEnum.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock,
|
||||
criteriaBuilderMock);
|
||||
|
||||
// verfication
|
||||
@@ -244,7 +265,7 @@ public class RSQLUtilityTest {
|
||||
|
||||
try {
|
||||
// test
|
||||
RSQLUtility.parse(correctRsql, TestFieldEnum.class).toPredicate(baseSoftwareModuleRootMock,
|
||||
RSQLUtility.parse(correctRsql, TestFieldEnum.class, null).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock, criteriaBuilderMock);
|
||||
fail("missing RSQLParameterUnsupportedFieldException for wrong enum value");
|
||||
} catch (final RSQLParameterUnsupportedFieldException e) {
|
||||
@@ -252,6 +273,67 @@ public class RSQLUtilityTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests the resolution of overdue_ts placeholder in context of a RSQL expression.")
|
||||
public void correctRsqlWithOverdueMacro() {
|
||||
reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
|
||||
final String overdueProp = "overdue_ts";
|
||||
final String overduePropPlaceholder = "${" + overdueProp + "}";
|
||||
final String correctRsql = "testfield=le=" + overduePropPlaceholder;
|
||||
when(baseSoftwareModuleRootMock.get("testfield")).thenReturn(baseSoftwareModuleRootMock);
|
||||
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class);
|
||||
when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class));
|
||||
when(criteriaBuilderMock.<String>lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder)))
|
||||
.thenReturn(mock(Predicate.class));
|
||||
|
||||
// test
|
||||
RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup())
|
||||
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
|
||||
|
||||
// verification
|
||||
verify(macroResolver).lookup(overdueProp);
|
||||
// the macro is already replaced when passed to #lessThanOrEqualTo -> the method is never invoked with the
|
||||
// placeholder:
|
||||
verify(criteriaBuilderMock, never()).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)),
|
||||
eq(overduePropPlaceholder));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests RSQL expression with an unknown placeholder.")
|
||||
public void correctRsqlWithUnknownMacro() {
|
||||
reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
|
||||
final String overdueProp = "unknown";
|
||||
final String overduePropPlaceholder = "${" + overdueProp + "}";
|
||||
final String correctRsql = "testfield=le=" + overduePropPlaceholder;
|
||||
when(baseSoftwareModuleRootMock.get("testfield")).thenReturn(baseSoftwareModuleRootMock);
|
||||
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class);
|
||||
when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class));
|
||||
when(criteriaBuilderMock.<String>lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder)))
|
||||
.thenReturn(mock(Predicate.class));
|
||||
|
||||
// test
|
||||
Predicate result = RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup())
|
||||
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
|
||||
|
||||
// verification
|
||||
verify(macroResolver).lookup(overdueProp);
|
||||
// the macro is unknown and hence never replaced -> #lessThanOrEqualTo is invoked with the placeholder:
|
||||
verify(criteriaBuilderMock).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)),
|
||||
eq(overduePropPlaceholder));
|
||||
}
|
||||
|
||||
public VirtualPropertyReplacer setupMacroLookup() {
|
||||
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class))
|
||||
.thenReturn(TEST_POLLING_TIME_INTERVAL);
|
||||
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class))
|
||||
.thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL);
|
||||
|
||||
mockStatic(TimestampCalculator.class);
|
||||
when(TimestampCalculator.getTenantConfigurationManagement()).thenReturn(confMgmt);
|
||||
|
||||
return macroResolver;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <Y> Path<Y> pathOfString(final Path<?> path) {
|
||||
return (Path<Y>) path;
|
||||
@@ -262,10 +344,8 @@ public class RSQLUtilityTest {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.hawkbit.server.rest.resource.model.FieldNameProvider#
|
||||
* getFieldName()
|
||||
*
|
||||
* @see org.eclipse.hawkbit.server.rest.resource.model.FieldNameProvider# getFieldName()
|
||||
*/
|
||||
@Override
|
||||
public String getFieldName() {
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.rsql;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.powermock.api.mockito.PowerMockito.mockStatic;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import org.apache.commons.lang3.text.StrSubstitutor;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.TimestampCalculator;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Unit Tests - Repository")
|
||||
@Stories("Placeholder resolution for virtual properties")
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest(TimestampCalculator.class)
|
||||
public class VirtualPropertyResolverTest {
|
||||
|
||||
@Spy
|
||||
private VirtualPropertyResolver resolverUnderTest = new VirtualPropertyResolver();
|
||||
|
||||
@Mock
|
||||
private TenantConfigurationManagement confMgmt;
|
||||
|
||||
private StrSubstitutor substitutor;
|
||||
|
||||
private Long nowTestTime;
|
||||
|
||||
private static final TenantConfigurationValue<String> TEST_POLLING_TIME_INTERVAL = TenantConfigurationValue
|
||||
.<String> builder().value("00:05:00").build();
|
||||
private static final TenantConfigurationValue<String> TEST_POLLING_OVERDUE_TIME_INTERVAL = TenantConfigurationValue
|
||||
.<String> builder().value("00:07:37").build();
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
nowTestTime = Instant.now().toEpochMilli();
|
||||
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class))
|
||||
.thenReturn(TEST_POLLING_TIME_INTERVAL);
|
||||
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class))
|
||||
.thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL);
|
||||
|
||||
mockStatic(TimestampCalculator.class);
|
||||
when(TimestampCalculator.getTenantConfigurationManagement()).thenReturn(confMgmt);
|
||||
|
||||
substitutor = new StrSubstitutor(resolverUnderTest,
|
||||
StrSubstitutor.DEFAULT_PREFIX,
|
||||
StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests resolution of NOW_TS by using a StrSubstitutor configured with the VirtualPropertyResolver.")
|
||||
public void resolveNowTimestampPlaceholder() {
|
||||
String placeholder = "${NOW_TS}";
|
||||
String testString = "lhs=lt=" + placeholder;
|
||||
|
||||
String resolvedPlaceholders = substitutor.replace(testString);
|
||||
assertThat("NOW_TS has to be resolved!", resolvedPlaceholders, not(containsString(placeholder)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests resolution of OVERDUE_TS by using a StrSubstitutor configured with the VirtualPropertyResolver.")
|
||||
public void resolveOverdueTimestampPlaceholder() {
|
||||
String placeholder = "${OVERDUE_TS}";
|
||||
String testString = "lhs=lt=" + placeholder;
|
||||
|
||||
String resolvedPlaceholders = substitutor.replace(testString);
|
||||
assertThat("OVERDUE_TS has to be resolved!", resolvedPlaceholders, not(containsString(placeholder)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests case insensititity of VirtualPropertyResolver.")
|
||||
public void resolveOverdueTimestampPlaceholderLowerCase() {
|
||||
String placeholder = "${overdue_ts}";
|
||||
String testString = "lhs=lt=" + placeholder;
|
||||
|
||||
String resolvedPlaceholders = substitutor.replace(testString);
|
||||
assertThat("overdue_ts has to be resolved!", resolvedPlaceholders, not(containsString(placeholder)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests VirtualPropertyResolver with a placeholder unknown to VirtualPropertyResolver.")
|
||||
public void handleUnknownPlaceholder() {
|
||||
String placeholder = "${unknown}";
|
||||
String testString = "lhs=lt=" + placeholder;
|
||||
|
||||
String resolvedPlaceholders = substitutor.replace(testString);
|
||||
assertThat("unknown should not be resolved!", resolvedPlaceholders, containsString(placeholder));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests escape mechanism for placeholders (syntax is $${SOME_PLACEHOLDER}).")
|
||||
public void handleEscapedPlaceholder() {
|
||||
String placeholder = "${OVERDUE_TS}";
|
||||
String escaptedPlaceholder = StrSubstitutor.DEFAULT_ESCAPE + placeholder;
|
||||
String testString = "lhs=lt=" + escaptedPlaceholder;
|
||||
|
||||
String resolvedPlaceholders = substitutor.replace(testString);
|
||||
assertThat("Escaped OVERDUE_TS should not be resolved!", resolvedPlaceholders, containsString(placeholder));
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@ import org.eclipse.hawkbit.cache.CacheConstants;
|
||||
import org.eclipse.hawkbit.cache.TenancyCacheManager;
|
||||
import org.eclipse.hawkbit.cache.TenantAwareCacheManager;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyResolver;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.repository.test.util.JpaTestRepositoryManagement;
|
||||
import org.eclipse.hawkbit.repository.test.util.TestRepositoryManagement;
|
||||
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
|
||||
@@ -129,4 +131,13 @@ public class TestConfiguration implements AsyncConfigurer {
|
||||
return new SimpleAsyncUncaughtExceptionHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return returns a VirtualPropertyReplacer
|
||||
*/
|
||||
@Bean
|
||||
public VirtualPropertyReplacer virtualPropertyReplacer() {
|
||||
return new VirtualPropertyResolver();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ public class DistributionSetTable extends AbstractNamedVersionTable<Distribution
|
||||
}
|
||||
|
||||
private boolean validateSoftwareModule(final SoftwareModule sm, final DistributionSet ds) {
|
||||
if (targetManagement.countTargetByFilters(null, null, ds.getId(), Boolean.FALSE, new String[] {}) > 0) {
|
||||
if (targetManagement.countTargetByFilters(null, null, null, ds.getId(), Boolean.FALSE, new String[] {}) > 0) {
|
||||
/* Distribution is already assigned */
|
||||
notification.displayValidationError(i18n.get("message.dist.inuse",
|
||||
HawkbitCommonUtil.concatStrings(":", ds.getName(), ds.getVersion())));
|
||||
|
||||
@@ -14,5 +14,39 @@ package org.eclipse.hawkbit.ui.management.event;
|
||||
*
|
||||
*/
|
||||
public enum ManagementUIEvent {
|
||||
SHOW_COUNT_MESSAGE, UPDATE_COUNT, UPDATE_FILTERCOUNT_MESSAGE, HIDE_TARGET_TAG_LAYOUT, SHOW_TARGET_TAG_LAYOUT, HIDE_DISTRIBUTION_TAG_LAYOUT, SHOW_DISTRIBUTION_TAG_LAYOUT, MAX_ACTION_HISTORY, MIN_ACTION_HISTORY, CLOSE_SAVE_ACTIONS_WINDOW, UNASSIGN_TARGET_TAG, UNASSIGN_DISTRIBUTION_TAG, ASSIGN_TARGET_TAG, ASSIGN_DISTRIBUTION_TAG, TARGET_TABLE_FILTER, RESET_SIMPLE_FILTERS, RESET_TARGET_FILTER_QUERY
|
||||
//
|
||||
SHOW_COUNT_MESSAGE,
|
||||
//
|
||||
UPDATE_COUNT,
|
||||
//
|
||||
UPDATE_FILTERCOUNT_MESSAGE,
|
||||
//
|
||||
HIDE_TARGET_TAG_LAYOUT,
|
||||
//
|
||||
SHOW_TARGET_TAG_LAYOUT,
|
||||
//
|
||||
HIDE_DISTRIBUTION_TAG_LAYOUT,
|
||||
//
|
||||
SHOW_DISTRIBUTION_TAG_LAYOUT,
|
||||
//
|
||||
MAX_ACTION_HISTORY,
|
||||
//
|
||||
MIN_ACTION_HISTORY,
|
||||
//
|
||||
CLOSE_SAVE_ACTIONS_WINDOW,
|
||||
//
|
||||
UNASSIGN_TARGET_TAG,
|
||||
//
|
||||
UNASSIGN_DISTRIBUTION_TAG,
|
||||
//
|
||||
ASSIGN_TARGET_TAG,
|
||||
//
|
||||
ASSIGN_DISTRIBUTION_TAG,
|
||||
//
|
||||
TARGET_TABLE_FILTER,
|
||||
//
|
||||
RESET_SIMPLE_FILTERS,
|
||||
//
|
||||
RESET_TARGET_FILTER_QUERY
|
||||
|
||||
}
|
||||
|
||||
@@ -14,5 +14,24 @@ package org.eclipse.hawkbit.ui.management.event;
|
||||
*
|
||||
*/
|
||||
public enum TargetFilterEvent {
|
||||
FILTER_BY_TEXT, FILTER_BY_TAG, REMOVE_FILTER_BY_TEXT, REMOVE_FILTER_BY_TAG, FILTER_BY_STATUS, FILTER_BY_DISTRIBUTION, REMOVE_FILTER_BY_STATUS, REMOVE_FILTER_BY_DISTRIBUTION, FILTER_BY_TARGET_FILTER_QUERY, REMOVE_FILTER_BY_TARGET_FILTER_QUERY
|
||||
//
|
||||
FILTER_BY_TEXT,
|
||||
//
|
||||
FILTER_BY_TAG,
|
||||
//
|
||||
REMOVE_FILTER_BY_TEXT,
|
||||
//
|
||||
REMOVE_FILTER_BY_TAG,
|
||||
//
|
||||
FILTER_BY_STATUS,
|
||||
//
|
||||
FILTER_BY_DISTRIBUTION,
|
||||
//
|
||||
REMOVE_FILTER_BY_STATUS,
|
||||
//
|
||||
REMOVE_FILTER_BY_DISTRIBUTION,
|
||||
//
|
||||
FILTER_BY_TARGET_FILTER_QUERY,
|
||||
//
|
||||
REMOVE_FILTER_BY_TARGET_FILTER_QUERY
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@ public class CountMessageLabel extends Label {
|
||||
}
|
||||
message.append(HawkbitCommonUtil.SP_STRING_PIPE);
|
||||
final String status = i18n.get("label.filter.status");
|
||||
final String overdue = i18n.get("label.filter.overdue");
|
||||
final String tags = i18n.get("label.filter.tags");
|
||||
final String text = i18n.get("label.filter.text");
|
||||
final String dists = i18n.get("label.filter.dist");
|
||||
@@ -148,6 +149,7 @@ public class CountMessageLabel extends Label {
|
||||
final StringBuilder filterMesgBuf = new StringBuilder(i18n.get("label.filter"));
|
||||
filterMesgBuf.append(HawkbitCommonUtil.SP_STRING_SPACE);
|
||||
filterMesgBuf.append(getStatusMsg(targFilParams.getClickedStatusTargetTags(), status));
|
||||
filterMesgBuf.append(getOverdueStateMsg(targFilParams.isOverdueFilterEnabled(), overdue));
|
||||
filterMesgBuf
|
||||
.append(getTagsMsg(targFilParams.isNoTagSelected(), targFilParams.getClickedTargetTags(), tags));
|
||||
filterMesgBuf.append(
|
||||
@@ -220,6 +222,17 @@ public class CountMessageLabel extends Label {
|
||||
return status.isEmpty() ? HawkbitCommonUtil.SP_STRING_SPACE : param;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Overdue State Message.
|
||||
*
|
||||
* @param overdueState
|
||||
* as flag
|
||||
* @return String as msg.
|
||||
*/
|
||||
private static String getOverdueStateMsg(final boolean overdueState, final String param) {
|
||||
return !overdueState ? HawkbitCommonUtil.SP_STRING_SPACE : param;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Tags Message.
|
||||
*
|
||||
|
||||
@@ -31,6 +31,8 @@ public class TargetTableFilters implements Serializable {
|
||||
|
||||
private final List<String> clickedTargetTags = new ArrayList<>();
|
||||
private final List<TargetUpdateStatus> clickedStatusTargetTags = new ArrayList<>();
|
||||
private boolean isOverdueFilterEnabled = Boolean.FALSE;
|
||||
|
||||
private String searchText;
|
||||
private DistributionSetIdName distributionSet;
|
||||
private Long pinnedDistId;
|
||||
@@ -130,7 +132,8 @@ public class TargetTableFilters implements Serializable {
|
||||
* {@code false}
|
||||
*/
|
||||
public boolean hasFilter() {
|
||||
return isFilteredByTextOrDs() || hasTagsSelected() || isFilteredByStatusOrCustomFilter();
|
||||
return isFilteredByTextOrDs() || hasTagsSelected() || isFilteredByStatusOrCustomFilter()
|
||||
|| isOverdueFilterEnabled();
|
||||
}
|
||||
|
||||
private boolean hasTagsSelected() {
|
||||
@@ -160,4 +163,12 @@ public class TargetTableFilters implements Serializable {
|
||||
this.targetFilterQuery = targetFilterQuery;
|
||||
}
|
||||
|
||||
public boolean isOverdueFilterEnabled() {
|
||||
return isOverdueFilterEnabled;
|
||||
}
|
||||
|
||||
public void setOverdueFilterEnabled(boolean isOverdueFilterEnabled) {
|
||||
this.isOverdueFilterEnabled = isOverdueFilterEnabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.management.targettable;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static org.apache.commons.lang3.ArrayUtils.isEmpty;
|
||||
import static org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil.isNotNullOrEmpty;
|
||||
import static org.eclipse.hawkbit.ui.utils.SPUIDefinitions.TARGET_TABLE_CREATE_AT_SORT_ORDER;
|
||||
@@ -19,6 +20,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.repository.FilterParams;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
@@ -52,6 +54,7 @@ public class TargetBeanQuery extends AbstractBeanQuery<ProxyTarget> {
|
||||
|
||||
private Sort sort = new Sort(TARGET_TABLE_CREATE_AT_SORT_ORDER, "createdAt");
|
||||
private transient Collection<TargetUpdateStatus> status;
|
||||
private transient Boolean overdueState;
|
||||
private String[] targetTags;
|
||||
private Long distributionId;
|
||||
private String searchText;
|
||||
@@ -81,6 +84,7 @@ public class TargetBeanQuery extends AbstractBeanQuery<ProxyTarget> {
|
||||
|
||||
if (isNotNullOrEmpty(queryConfig)) {
|
||||
status = (Collection<TargetUpdateStatus>) queryConfig.get(SPUIDefinitions.FILTER_BY_STATUS);
|
||||
overdueState = (Boolean) queryConfig.get(SPUIDefinitions.FILTER_BY_OVERDUE_STATE);
|
||||
targetTags = (String[]) queryConfig.get(SPUIDefinitions.FILTER_BY_TAG);
|
||||
noTagClicked = (Boolean) queryConfig.get(SPUIDefinitions.FILTER_BY_NO_TAG);
|
||||
distributionId = (Long) queryConfig.get(SPUIDefinitions.FILTER_BY_DISTRIBUTION);
|
||||
@@ -114,17 +118,17 @@ public class TargetBeanQuery extends AbstractBeanQuery<ProxyTarget> {
|
||||
if (pinnedDistId != null) {
|
||||
targetBeans = getTargetManagement().findTargetsAllOrderByLinkedDistributionSet(
|
||||
new OffsetBasedPageRequest(startIndex, SPUIDefinitions.PAGE_SIZE, sort), pinnedDistId,
|
||||
distributionId, status, searchText, noTagClicked, targetTags);
|
||||
new FilterParams(distributionId, status, overdueState, searchText, noTagClicked, targetTags));
|
||||
} else if (null != targetFilterQuery) {
|
||||
targetBeans = getTargetManagement().findTargetsAll(targetFilterQuery,
|
||||
new PageRequest(startIndex / SPUIDefinitions.PAGE_SIZE, SPUIDefinitions.PAGE_SIZE, sort));
|
||||
} else if (!anyFilterSelected()) {
|
||||
} else if (!isAnyFilterSelected()) {
|
||||
targetBeans = getTargetManagement().findTargetsAll(
|
||||
new PageRequest(startIndex / SPUIDefinitions.PAGE_SIZE, SPUIDefinitions.PAGE_SIZE, sort));
|
||||
} else {
|
||||
targetBeans = getTargetManagement().findTargetByFilters(
|
||||
new PageRequest(startIndex / SPUIDefinitions.PAGE_SIZE, SPUIDefinitions.PAGE_SIZE, sort), status,
|
||||
searchText, distributionId, noTagClicked, targetTags);
|
||||
overdueState, searchText, distributionId, noTagClicked, targetTags);
|
||||
}
|
||||
for (final Target targ : targetBeans) {
|
||||
final ProxyTarget prxyTarget = new ProxyTarget();
|
||||
@@ -170,31 +174,27 @@ public class TargetBeanQuery extends AbstractBeanQuery<ProxyTarget> {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isOverdueFilterEnabled() {
|
||||
return Boolean.TRUE.equals(overdueState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveBeans(final List<ProxyTarget> addedTargets, final List<ProxyTarget> modifiedTargets,
|
||||
final List<ProxyTarget> removedTargets) {
|
||||
// CRUD operations on Target will be done through repository methods
|
||||
}
|
||||
|
||||
private Boolean anyFilterSelected() {
|
||||
if (CollectionUtils.isEmpty(status) && distributionId == null && Strings.isNullOrEmpty(searchText)
|
||||
&& !isTagSelected()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
final long totSize = getTargetManagement().countTargetsAll();
|
||||
long size;
|
||||
if (null != targetFilterQuery) {
|
||||
size = getTargetManagement().countTargetByTargetFilterQuery(targetFilterQuery);
|
||||
} else if (!anyFilterSelected()) {
|
||||
} else if (!isAnyFilterSelected()) {
|
||||
size = totSize;
|
||||
} else {
|
||||
size = getTargetManagement().countTargetByFilters(status, searchText, distributionId, noTagClicked,
|
||||
targetTags);
|
||||
size = getTargetManagement().countTargetByFilters(status, overdueState, searchText, distributionId,
|
||||
noTagClicked, targetTags);
|
||||
}
|
||||
|
||||
final ManagementUIState tmpManagementUIState = getManagementUIState();
|
||||
@@ -209,6 +209,11 @@ public class TargetBeanQuery extends AbstractBeanQuery<ProxyTarget> {
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
private boolean isAnyFilterSelected() {
|
||||
final boolean isFilterSelected = isTagSelected() || isOverdueFilterEnabled();
|
||||
return isFilterSelected || CollectionUtils.isNotEmpty(status) || distributionId != null || !isNullOrEmpty(searchText);
|
||||
}
|
||||
|
||||
private TargetManagement getTargetManagement() {
|
||||
if (targetManagement == null) {
|
||||
targetManagement = SpringContextHelper.getBean(TargetManagement.class);
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.eclipse.hawkbit.repository.FilterParams;
|
||||
import org.eclipse.hawkbit.repository.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent;
|
||||
@@ -411,6 +412,9 @@ public class TargetTable extends AbstractTable<Target, TargetIdName> {
|
||||
.getClickedStatusTargetTags();
|
||||
queryConfig.put(SPUIDefinitions.FILTER_BY_STATUS, statusList);
|
||||
}
|
||||
if (managementUIState.getTargetTableFilters().isOverdueFilterEnabled()) {
|
||||
queryConfig.put(SPUIDefinitions.FILTER_BY_OVERDUE_STATE, Boolean.TRUE);
|
||||
}
|
||||
return queryConfig;
|
||||
}
|
||||
|
||||
@@ -461,7 +465,7 @@ public class TargetTable extends AbstractTable<Target, TargetIdName> {
|
||||
/**
|
||||
* Add listener to pin.
|
||||
*
|
||||
* @param pinBtn
|
||||
* @param event
|
||||
* as event
|
||||
*/
|
||||
private void addPinClickListener(final ClickEvent event) {
|
||||
@@ -843,6 +847,7 @@ public class TargetTable extends AbstractTable<Target, TargetIdName> {
|
||||
managementUIState.setTargetsCountAll(totalTargetsCount);
|
||||
|
||||
Collection<TargetUpdateStatus> status = null;
|
||||
Boolean overdueState = null;
|
||||
String[] targetTags = null;
|
||||
Long distributionId = null;
|
||||
String searchText = null;
|
||||
@@ -854,6 +859,9 @@ public class TargetTable extends AbstractTable<Target, TargetIdName> {
|
||||
if (isFilteredByStatus()) {
|
||||
status = managementUIState.getTargetTableFilters().getClickedStatusTargetTags();
|
||||
}
|
||||
if (managementUIState.getTargetTableFilters().isOverdueFilterEnabled()) {
|
||||
overdueState = managementUIState.getTargetTableFilters().isOverdueFilterEnabled();
|
||||
}
|
||||
if (managementUIState.getTargetTableFilters().getDistributionSet().isPresent()) {
|
||||
distributionId = managementUIState.getTargetTableFilters().getDistributionSet().get().getId();
|
||||
}
|
||||
@@ -865,25 +873,29 @@ public class TargetTable extends AbstractTable<Target, TargetIdName> {
|
||||
pinnedDistId = managementUIState.getTargetTableFilters().getPinnedDistId().get();
|
||||
}
|
||||
|
||||
final long size = getTargetsCountWithFilter(totalTargetsCount, status, targetTags, distributionId, searchText,
|
||||
noTagClicked, pinnedDistId);
|
||||
final long size = getTargetsCountWithFilter(totalTargetsCount, pinnedDistId,
|
||||
new FilterParams(distributionId, status, overdueState, searchText, noTagClicked, targetTags));
|
||||
|
||||
if (size > SPUIDefinitions.MAX_TABLE_ENTRIES) {
|
||||
managementUIState.setTargetsTruncated(size - SPUIDefinitions.MAX_TABLE_ENTRIES);
|
||||
}
|
||||
}
|
||||
|
||||
private long getTargetsCountWithFilter(final long totalTargetsCount, final Collection<TargetUpdateStatus> status,
|
||||
final String[] targetTags, final Long distributionId, final String searchText, final Boolean noTagClicked,
|
||||
final Long pinnedDistId) {
|
||||
private long getTargetsCountWithFilter(final long totalTargetsCount,
|
||||
final Long pinnedDistId, final FilterParams filterParams) {
|
||||
final long size;
|
||||
if (managementUIState.getTargetTableFilters().getTargetFilterQuery().isPresent()) {
|
||||
size = targetManagement.countTargetByTargetFilterQuery(
|
||||
managementUIState.getTargetTableFilters().getTargetFilterQuery().get());
|
||||
} else if (noFilterSelected(status, pinnedDistId, noTagClicked, targetTags, searchText)) {
|
||||
} else if (noFilterSelected(filterParams.getFilterByStatus(), pinnedDistId,
|
||||
filterParams.getSelectTargetWithNoTag(), filterParams.getFilterByTagNames(),
|
||||
filterParams.getFilterBySearchText())) {
|
||||
size = totalTargetsCount;
|
||||
} else {
|
||||
size = targetManagement.countTargetByFilters(status, searchText, distributionId, noTagClicked, targetTags);
|
||||
size = targetManagement.countTargetByFilters(filterParams.getFilterByStatus(),
|
||||
filterParams.getOverdueState(), filterParams.getFilterBySearchText(),
|
||||
filterParams.getFilterByDistributionId(), filterParams.getSelectTargetWithNoTag(),
|
||||
filterParams.getFilterByTagNames());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -54,16 +54,20 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click
|
||||
@Autowired
|
||||
private ManagementUIState managementUIState;
|
||||
|
||||
private static final String OVERDUE_CAPTION = "overdue";
|
||||
|
||||
private Button unknown;
|
||||
private Button inSync;
|
||||
private Button pending;
|
||||
private Button error;
|
||||
private Button registered;
|
||||
private Button overdue;
|
||||
private Boolean unknownBtnClicked = false;
|
||||
private Boolean errorBtnClicked = false;
|
||||
private Boolean pendingBtnClicked = false;
|
||||
private Boolean inSyncBtnClicked = false;
|
||||
private Boolean registeredBtnClicked = false;
|
||||
private Boolean overdueBtnClicked = false;
|
||||
private Button buttonClicked;
|
||||
private static final String BTN_CLICKED = "btnClicked";
|
||||
|
||||
@@ -103,7 +107,17 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click
|
||||
buttonLayout.addComponent(registered);
|
||||
buttonLayout.setComponentAlignment(registered, Alignment.MIDDLE_CENTER);
|
||||
addComponent(buttonLayout);
|
||||
setComponentAlignment(buttonLayout, Alignment.MIDDLE_CENTER);
|
||||
setComponentAlignment(buttonLayout, Alignment.MIDDLE_LEFT);
|
||||
|
||||
final HorizontalLayout overdueLayout = new HorizontalLayout();
|
||||
final Label overdueLabel = new LabelBuilder().name(i18n.get("label.filter.by.overdue")).buildLabel();
|
||||
overdueLayout.setStyleName("overdue-button-layout");
|
||||
overdueLayout.addComponent(overdue);
|
||||
overdueLayout.setComponentAlignment(overdue, Alignment.MIDDLE_LEFT);
|
||||
overdueLayout.addComponent(overdueLabel);
|
||||
overdueLayout.setComponentAlignment(overdueLabel, Alignment.MIDDLE_LEFT);
|
||||
addComponent(overdueLayout);
|
||||
setComponentAlignment(overdueLayout, Alignment.MIDDLE_LEFT);
|
||||
|
||||
}
|
||||
|
||||
@@ -129,6 +143,10 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click
|
||||
}
|
||||
}
|
||||
}
|
||||
if (managementUIState.getTargetTableFilters().isOverdueFilterEnabled()) {
|
||||
overdue.addStyleName(BTN_CLICKED);
|
||||
overdueBtnClicked = Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,18 +168,23 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click
|
||||
registered = SPUIComponentProvider.getButton(UIComponentIdProvider.REGISTERED_STATUS_ICON,
|
||||
TargetUpdateStatus.REGISTERED.toString(), i18n.get("tooltip.status.registered"),
|
||||
SPUIButtonDefinitions.SP_BUTTON_STATUS_STYLE, false, FontAwesome.SQUARE, SPUIButtonStyleSmall.class);
|
||||
overdue = SPUIComponentProvider.getButton(UIComponentIdProvider.OVERDUE_STATUS_ICON,
|
||||
OVERDUE_CAPTION, i18n.get("tooltip.status.overdue"),
|
||||
SPUIButtonDefinitions.SP_BUTTON_STATUS_STYLE, false, FontAwesome.SQUARE, SPUIButtonStyleSmall.class);
|
||||
applyStatusBtnStyle();
|
||||
unknown.setData("filterStatusOne");
|
||||
inSync.setData("filterStatusTwo");
|
||||
pending.setData("filterStatusThree");
|
||||
error.setData("filterStatusFour");
|
||||
registered.setData("filterStatusFive");
|
||||
overdue.setData("filterStatusSix");
|
||||
|
||||
unknown.addClickListener(this);
|
||||
inSync.addClickListener(this);
|
||||
pending.addClickListener(this);
|
||||
error.addClickListener(this);
|
||||
registered.addClickListener(this);
|
||||
overdue.addClickListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,6 +196,7 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click
|
||||
pending.addStyleName("pendingBtn");
|
||||
error.addStyleName("errorBtn");
|
||||
registered.addStyleName("registeredBtn");
|
||||
overdue.addStyleName("overdueBtn");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -188,6 +212,8 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click
|
||||
processErrorFilterStatus();
|
||||
} else if (event.getButton().getCaption().equalsIgnoreCase(TargetUpdateStatus.REGISTERED.toString())) {
|
||||
processRegisteredFilterStatus();
|
||||
} else if (event.getButton().getCaption().equalsIgnoreCase(OVERDUE_CAPTION)) {
|
||||
processOverdueFilterStatus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,9 +257,26 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click
|
||||
processCommonFilterStatus(TargetUpdateStatus.REGISTERED, registeredBtnClicked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process - OVERDUE.
|
||||
*/
|
||||
private void processOverdueFilterStatus() {
|
||||
overdueBtnClicked = !overdueBtnClicked;
|
||||
managementUIState.getTargetTableFilters().setOverdueFilterEnabled(overdueBtnClicked);
|
||||
|
||||
if (overdueBtnClicked) {
|
||||
buttonClicked.addStyleName(BTN_CLICKED);
|
||||
eventBus.publish(this, TargetFilterEvent.FILTER_BY_STATUS);
|
||||
} else {
|
||||
buttonClicked.removeStyleName(BTN_CLICKED);
|
||||
eventBus.publish(this, TargetFilterEvent.REMOVE_FILTER_BY_STATUS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Process - COMMON PROCESS.
|
||||
*
|
||||
*
|
||||
* @param status
|
||||
* as enum
|
||||
* @param buttonReset
|
||||
@@ -268,11 +311,12 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click
|
||||
inSync.removeStyleName(BTN_CLICKED);
|
||||
error.removeStyleName(BTN_CLICKED);
|
||||
pending.removeStyleName(BTN_CLICKED);
|
||||
overdue.removeStyleName(BTN_CLICKED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any status button in clicked.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private boolean isStatusFilterApplied() {
|
||||
|
||||
@@ -205,6 +205,12 @@ public final class SPUIDefinitions {
|
||||
* Filter by status key.
|
||||
*/
|
||||
public static final String FILTER_BY_STATUS = "FilterByStatus";
|
||||
|
||||
/**
|
||||
* Filter by overdue state key.
|
||||
*/
|
||||
public static final String FILTER_BY_OVERDUE_STATE = "FilterByOverdueState";
|
||||
|
||||
/**
|
||||
* Filter by tag key.
|
||||
*/
|
||||
@@ -505,7 +511,7 @@ public final class SPUIDefinitions {
|
||||
|
||||
/**
|
||||
* Get the locales
|
||||
*
|
||||
*
|
||||
* @return the availableLocales
|
||||
*/
|
||||
public static Set<String> getAvailableLocales() {
|
||||
|
||||
@@ -189,6 +189,10 @@ public final class UIComponentIdProvider {
|
||||
* REGISTERED_STATUS_ICON ID.
|
||||
*/
|
||||
public static final String REGISTERED_STATUS_ICON = "registered.status.icon";
|
||||
/**
|
||||
* OVERDUE_STATUS_ICON ID.
|
||||
*/
|
||||
public static final String OVERDUE_STATUS_ICON = "overdue.status.icon";
|
||||
/**
|
||||
* DROP filter icon id.
|
||||
*/
|
||||
|
||||
@@ -13,8 +13,11 @@
|
||||
$unknown-color: $status-unknown-color;
|
||||
$in-sync-color: $signal-green-color;
|
||||
$pending-color: $signal-yellow-color;
|
||||
$error-color: $signal-red-color;
|
||||
$registered-color: $bosch-color-light-blue;
|
||||
$error-color: $signal-red-color;
|
||||
$registered-color: $signal-light-blue-color;
|
||||
|
||||
//Overdue filter button color
|
||||
$overdue-color: $signal-dark-blue-color;
|
||||
|
||||
//Filter by status buttons group alignment
|
||||
.target-status-filters {
|
||||
@@ -27,6 +30,10 @@
|
||||
.status-button-layout {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
.overdue-button-layout {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
//Filter Button applied with below styles based on the color
|
||||
.unknownBtn {
|
||||
@@ -68,6 +75,16 @@
|
||||
.errorBtn:active:after {
|
||||
border-color: $error-color;
|
||||
}
|
||||
|
||||
.overdueBtn {
|
||||
background: $overdue-color;
|
||||
border: solid 3px $overdue-color;
|
||||
}
|
||||
|
||||
.overdueBtn:focus:after,
|
||||
.overdueBtn:active:after {
|
||||
border-color: $overdue-color;
|
||||
}
|
||||
|
||||
.registeredBtn {
|
||||
background: $registered-color;
|
||||
|
||||
@@ -101,10 +101,13 @@ $details-tab-caption-font-scale: .8;
|
||||
//Generic text style
|
||||
$generic-text-font-scale: .85;
|
||||
|
||||
$status-unknown-color: #3085cb;
|
||||
$status-unknown-color: #d5d5d5;
|
||||
$signal-green-color: #6eb553;
|
||||
$signal-yellow-color: #ff0;
|
||||
$signal-light-blue-color: #3085cb;
|
||||
$signal-dark-blue-color: #26547a;
|
||||
$signal-red-color: #f00;
|
||||
$signal-black-color: #000;
|
||||
$signal-orange-color: #ffa500;
|
||||
|
||||
$grey-light: #d5d5d5;
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
}
|
||||
|
||||
.statusIconLightBlue {
|
||||
color: $bosch-color-light-blue;
|
||||
color: $signal-light-blue-color;
|
||||
}
|
||||
|
||||
.v-button-statusIconLightBlue:after {
|
||||
@@ -219,7 +219,7 @@
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
.blueSpinner{
|
||||
@include valo-spinner($size: $v-font-size--small,$color: $bosch-color-light-blue);
|
||||
@include valo-spinner($size: $v-font-size--small,$color: $signal-light-blue-color);
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
@mixin target-filter-query {
|
||||
|
||||
.gwt-MenuBar-autocomplete {
|
||||
cursor: default;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
|
||||
.gwt-MenuBar-autocomplete .gwt-MenuItem{
|
||||
border-radius: 3px !important;
|
||||
cursor: pointer !important;
|
||||
@@ -21,7 +21,7 @@
|
||||
position: relative !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
|
||||
.gwt-MenuBar-autocomplete .gwt-MenuItem-selected {
|
||||
background-color: $hawkbit-primary-color;
|
||||
background-image: linear-gradient(to bottom, #1b87e3 2%, #166ed5 98%) !important;
|
||||
|
||||
@@ -148,6 +148,7 @@ label.filter.selected = Selected :
|
||||
label.filter.shown = Shown :
|
||||
label.filter.targets = Filtered Targets :
|
||||
label.filter.status = Status,
|
||||
label.filter.overdue = Overdue,
|
||||
label.filter.tags = Tags,
|
||||
label.filter.text = Search Text
|
||||
label.filter.dist = Distribution,
|
||||
@@ -168,6 +169,7 @@ label.target.id = Controller Id :
|
||||
label.target.ip = Controller IP :
|
||||
label.target.security.token = Security token :
|
||||
label.filter.by.status = Filter by Status
|
||||
label.filter.by.overdue = Filter by Overdue
|
||||
label.target.controller.attrs = <b>Controller attributes</b>
|
||||
label.target.lastpolldate = Last poll :
|
||||
label.tag.name = Tag name
|
||||
@@ -203,6 +205,7 @@ tooltip.status.registered = Registered
|
||||
tooltip.status.pending = Pending
|
||||
tooltip.status.error = Error
|
||||
tooltip.status.insync = In-sync
|
||||
tooltip.status.overdue = Overdue
|
||||
tooltip.delete.module = Select and delete Software Module
|
||||
tooltip.forced.item=Forced update action
|
||||
tooltip.soft.item=Soft update action which interacts with an user as a attempt update action for example
|
||||
|
||||
14
pom.xml
14
pom.xml
@@ -133,7 +133,7 @@
|
||||
<org.easytesting.version>2.0M10</org.easytesting.version>
|
||||
<allure.version>1.4.22</allure.version>
|
||||
<eclipselink.version>2.6.2</eclipselink.version>
|
||||
<org.powermock.version>1.5.4</org.powermock.version>
|
||||
<org.powermock.version>1.6.5</org.powermock.version>
|
||||
<pl.pragmatists.version>1.0.2</pl.pragmatists.version>
|
||||
<guava.version>19.0</guava.version>
|
||||
<mariadb-java-client.version>1.5.3</mariadb-java-client.version>
|
||||
@@ -675,6 +675,18 @@
|
||||
<version>${pl.pragmatists.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>${org.powermock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito</artifactId>
|
||||
<version>${org.powermock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mariadb.jdbc</groupId>
|
||||
<artifactId>mariadb-java-client</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user