Fix sonar issues and add DMF tests for maintenance window feature (#655)

* Fix sonar issues.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* POM cleanup and more sonar issues fixed.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Remove unneeded JavaDocs.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* More sonar issues.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* More issues.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Adapt maintenance window to naming.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Add DMF tests.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Readibility.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Typos fixed.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
Kai Zimmermann
2018-03-08 10:42:25 +01:00
committed by GitHub
parent f4278c45ef
commit b4414438b0
32 changed files with 411 additions and 364 deletions

View File

@@ -236,7 +236,7 @@ public interface ControllerManagement {
* {@link TenantConfigurationKey#MAINTENANCE_WINDOW_POLL_COUNT}.
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
public int getMaintenanceWindowPollCount();
int getMaintenanceWindowPollCount();
/**
* Returns polling time based on the maintenance window for an action.
@@ -248,14 +248,14 @@ public interface ControllerManagement {
* of maintenance window, it resets to default
* {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}.
*
* @param action
* @param actionId
* id the {@link Action} for which polling time is calculated
* based on it having maintenance window or not
*
* @return current {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}.
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
String getPollingTimeForAction(final Action action);
String getPollingTimeForAction(long actionId);
/**
* Checks if a given target has currently or has even been assigned to the

View File

@@ -16,10 +16,9 @@ import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.util.Optional;
import java.util.TimeZone;
import java.util.regex.Pattern;
import org.eclipse.hawkbit.repository.exception.InvalidMaintenanceScheduleException;
import org.springframework.util.StringUtils;
import com.cronutils.model.Cron;
import com.cronutils.model.definition.CronDefinition;
@@ -35,9 +34,7 @@ import com.cronutils.parser.CronParser;
*/
public class MaintenanceScheduleHelper {
ExecutionTime scheduleExecutor = null;
Duration duration = null;
TimeZone timeZone = null;
private final ExecutionTime scheduleExecutor;
/**
* Constructor that accepts a cron expression, duration and time zone and
@@ -48,22 +45,11 @@ public class MaintenanceScheduleHelper {
* maintenance window. Expression has 6 mandatory fields and 1
* last optional field: "second minute hour dayofmonth month
* weekday year"
* @param duration
* in HH:mm:ss format specifying the duration of a maintenance
* window, for example 00:30:00 for 30 minutes
* @param timezone
* is the time zone specified as +/-hh:mm offset from UTC. For
* example +02:00 for CET summer time and +00:00 for UTC. The
* start time of a maintenance window calculated based on the
* cron expression is relative to this time zone.
*/
public MaintenanceScheduleHelper(String cronSchedule, String duration, String timeZone) {
this.timeZone = TimeZone.getTimeZone(ZoneOffset.of(timeZone));
this.duration = Duration.parse(convertToISODuration(duration));
CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(QUARTZ);
CronParser parser = new CronParser(cronDefinition);
Cron quartzCron = parser.parse(cronSchedule);
public MaintenanceScheduleHelper(final String cronSchedule) {
final CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(QUARTZ);
final CronParser parser = new CronParser(cronDefinition);
final Cron quartzCron = parser.parse(cronSchedule);
this.scheduleExecutor = ExecutionTime.forCron(quartzCron);
}
@@ -78,11 +64,13 @@ public class MaintenanceScheduleHelper {
* @return {@link Optional<ZonedDateTime>} of the next available window. In
* case there is none, returns empty value.
*/
public Optional<ZonedDateTime> nextExecution(ZonedDateTime after) {
// Exception squid:S1166 - lib throws exception as well if no value found
@SuppressWarnings("squid:S1166")
public Optional<ZonedDateTime> nextExecution(final ZonedDateTime after) {
try {
ZonedDateTime next = this.scheduleExecutor.nextExecution(after);
return Optional.of(next);
} catch (IllegalArgumentException e) {
final ZonedDateTime next = this.scheduleExecutor.nextExecution(after);
return Optional.ofNullable(next);
} catch (final IllegalArgumentException ignored) {
return Optional.empty();
}
}
@@ -98,7 +86,7 @@ public class MaintenanceScheduleHelper {
* @return true if there is at least one valid schedule remaining, else
* false.
*/
public boolean hasValidScheduleAfter(ZonedDateTime after) {
private boolean hasValidScheduleAfter(final ZonedDateTime after) {
return nextExecution(after).isPresent();
}
@@ -122,34 +110,41 @@ public class MaintenanceScheduleHelper {
* start time of a maintenance window calculated based on the
* cron expression is relative to this time zone
*
* @return true if the schedule is valid, else throw an exception
*
* @throws InvalidMaintenanceScheduleException
* if the defined schedule fails the validity criteria.
*/
public static boolean validateMaintenanceSchedule(String cronSchedule, String duration, String timezone) {
// check if schedule, duration and timezone are all not null.
if (cronSchedule != null && duration != null && timezone != null) {
// check if schedule, duration and timezone are all not empty.
if (!(cronSchedule.isEmpty() || duration.isEmpty() || timezone.isEmpty())) {
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.of(timezone));
MaintenanceScheduleHelper scheduleHelper = new MaintenanceScheduleHelper(cronSchedule, duration,
timezone);
// check if there is a window currently active or available in
// future.
if (!scheduleHelper.hasValidScheduleAfter(now.minus(Duration.parse(convertToISODuration(duration))))) {
throw new InvalidMaintenanceScheduleException(
"No valid maintenance window available after current time");
}
} else {
throw new InvalidMaintenanceScheduleException("Either of schedule, duration or timezone empty.");
public static void validateMaintenanceSchedule(final String cronSchedule, final String duration,
final String timezone) {
// check if schedule, duration and timezone are all not empty.
if (allNotEmpty(cronSchedule, duration, timezone)) {
final ZonedDateTime now;
try {
now = ZonedDateTime.now(ZoneOffset.of(timezone));
Duration.parse(convertToISODuration(duration));
} catch (final RuntimeException validationFailed) {
throw new InvalidMaintenanceScheduleException("No valid maintenance window provided", validationFailed);
}
} else if (!(cronSchedule == null && duration == null && timezone == null)) {
final MaintenanceScheduleHelper scheduleHelper = new MaintenanceScheduleHelper(cronSchedule);
// check if there is a window currently active or available in
// future.
if (!scheduleHelper.hasValidScheduleAfter(now.minus(Duration.parse(convertToISODuration(duration))))) {
throw new InvalidMaintenanceScheduleException(
"No valid maintenance window available after current time");
}
} else if (atLeastOneNotEmpty(cronSchedule, duration, timezone)) {
throw new InvalidMaintenanceScheduleException(
"All of schedule, duration and timezone should either be null or non empty.");
}
}
return true;
private static boolean atLeastOneNotEmpty(final String cronSchedule, final String duration, final String timezone) {
return !(StringUtils.isEmpty(cronSchedule) && StringUtils.isEmpty(duration) && StringUtils.isEmpty(timezone));
}
private static boolean allNotEmpty(final String cronSchedule, final String duration, final String timezone) {
return !StringUtils.isEmpty(cronSchedule) && !StringUtils.isEmpty(duration) && !StringUtils.isEmpty(timezone);
}
/**
@@ -166,7 +161,7 @@ public class MaintenanceScheduleHelper {
* @throws DateTimeParseException
* if the text cannot be converted to ISO format.
*/
public static String convertToISODuration(String timeInterval) {
public static String convertToISODuration(final String timeInterval) {
return Duration.between(LocalTime.MIN, LocalTime.parse(timeInterval)).toString();
}
}

View File

@@ -26,6 +26,8 @@ public class TargetAssignDistributionSetEvent extends RemoteTenantAwareEvent {
private long distributionSetId;
private boolean maintenanceWindowAvailable;
private final Map<String, Long> actions = new HashMap<>();
/**
@@ -46,24 +48,32 @@ public class TargetAssignDistributionSetEvent extends RemoteTenantAwareEvent {
* the actions and the targets
* @param applicationId
* the application id.
* @param maintenanceWindowAvailable
* see {@link Action#isMaintenanceWindowAvailable()}
*/
public TargetAssignDistributionSetEvent(final String tenant, final long distributionSetId, final List<Action> a,
final String applicationId) {
final String applicationId, final boolean maintenanceWindowAvailable) {
super(distributionSetId, tenant, applicationId);
this.distributionSetId = distributionSetId;
this.maintenanceWindowAvailable = maintenanceWindowAvailable;
actions.putAll(a.stream().filter(action -> action.getDistributionSet().getId().longValue() == distributionSetId)
.collect(Collectors.toMap(action -> action.getTarget().getControllerId(), Action::getId)));
}
public TargetAssignDistributionSetEvent(final Action action, final String applicationId) {
this(action.getTenant(), action.getDistributionSet().getId(), Arrays.asList(action), applicationId);
this(action.getTenant(), action.getDistributionSet().getId(), Arrays.asList(action), applicationId,
action.isMaintenanceWindowAvailable());
}
public Long getDistributionSetId() {
return distributionSetId;
}
public boolean isMaintenanceWindowAvailable() {
return maintenanceWindowAvailable;
}
public Map<String, Long> getActions() {
return actions;
}

View File

@@ -14,8 +14,6 @@ import org.eclipse.hawkbit.repository.model.Action.ActionType;
/**
* A custom view on {@link Target} with {@link ActionType}.
*
*
*
*/
public class TargetWithActionType {
@@ -23,9 +21,9 @@ public class TargetWithActionType {
private final String controllerId;
private final ActionType actionType;
private final long forceTime;
private String maintenanceSchedule = null;
private String maintenanceWindowDuration = null;
private String maintenanceWindowTimeZone = null;
private String maintenanceSchedule;
private String maintenanceWindowDuration;
private String maintenanceWindowTimeZone;
public TargetWithActionType(final String controllerId) {
this.controllerId = controllerId;
@@ -35,7 +33,7 @@ public class TargetWithActionType {
public TargetWithActionType(final String controllerId, final ActionType actionType, final long forceTime) {
this.controllerId = controllerId;
this.actionType = actionType;
this.actionType = actionType != null ? actionType : ActionType.FORCED;
this.forceTime = forceTime;
}
@@ -64,19 +62,16 @@ public class TargetWithActionType {
* if the parameters do not define a valid maintenance schedule.
*/
public TargetWithActionType(final String controllerId, final ActionType actionType, final long forceTime,
String maintenanceSchedule, String maintenanceWindowDuration, String maintenanceWindowTimeZone) {
this.controllerId = controllerId;
this.actionType = actionType;
this.forceTime = forceTime;
final String maintenanceSchedule, final String maintenanceWindowDuration,
final String maintenanceWindowTimeZone) {
this(controllerId, actionType, forceTime);
if (MaintenanceScheduleHelper.validateMaintenanceSchedule(maintenanceSchedule, maintenanceWindowDuration,
maintenanceWindowTimeZone)) {
this.maintenanceSchedule = maintenanceSchedule;
this.maintenanceWindowDuration = maintenanceWindowDuration;
this.maintenanceWindowTimeZone = maintenanceWindowTimeZone;
} else {
throw new InvalidMaintenanceScheduleException("Invalid maintenance window definition");
}
this.maintenanceSchedule = maintenanceSchedule;
this.maintenanceWindowDuration = maintenanceWindowDuration;
this.maintenanceWindowTimeZone = maintenanceWindowTimeZone;
MaintenanceScheduleHelper.validateMaintenanceSchedule(maintenanceSchedule, maintenanceWindowDuration,
maintenanceWindowTimeZone);
}
public ActionType getActionType() {