Skip to content

Commit

Permalink
chore: Refactor wait-for commands (closes #350)
Browse files Browse the repository at this point in the history
  • Loading branch information
rsenden committed Jul 31, 2023
1 parent 76aac76 commit 8826407
Show file tree
Hide file tree
Showing 26 changed files with 275 additions and 225 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ private void checkOptionNames(Results results, CommandSpec cmdSpec, OptionSpec o

private void checkMultiValueOption(Results results, CommandSpec cmdSpec, OptionSpec optionSpec) {
if ( optionSpec.isMultiValue() ) {
Stream.of(optionSpec.names()).filter(n->n.startsWith("--") && !n.endsWith("s")).forEach(
Stream.of(optionSpec.names()).filter(n->n.startsWith("--") && !n.endsWith("s") && !n.contains("any")).forEach(
name->results.add(TestType.MULTI_OPT_PLURAL_NAME, Level.ERROR, cmdSpec, optionSpec, "Multi-value option should use plural option name: "+name));
if ( StringUtils.isBlank(optionSpec.splitRegex()) ) {
results.add(TestType.MULTI_OPT_SPLIT, Level.ERROR, cmdSpec, optionSpec, "Multi-value option should define a split expression");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ public TypeComparator getTypeComparator() {
* @see org.springframework.expression.EvaluationContext#getOperatorOverloader()
*/
public OperatorOverloader getOperatorOverloader() {
System.err.println("getOperatorOverloader()");
// TODO Return out custom overloader
return delegate.getOperatorOverloader();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import com.fortify.cli.common.output.transform.IActionCommandResultSupplier;
import com.fortify.cli.common.output.writer.ISingularSupplier;
import com.fortify.cli.common.rest.cli.mixin.StandardWaitHelperProgressMonitorMixin;
import com.fortify.cli.common.rest.cli.mixin.WaitHelperControlOptions;
import com.fortify.cli.common.rest.cli.mixin.WaitHelperWaitOptions;
import com.fortify.cli.common.rest.cli.mixin.WaitHelperControlPropertiesMixin;
import com.fortify.cli.common.rest.cli.mixin.WaitHelperWaitTypeMixin;
import com.fortify.cli.common.rest.unirest.IUnirestInstanceSupplier;
import com.fortify.cli.common.rest.wait.WaitHelper;
import com.fortify.cli.common.rest.wait.WaitHelper.WaitHelperBuilder;
Expand All @@ -30,8 +30,8 @@

public abstract class AbstractWaitForCommand extends AbstractRunnableCommand implements IActionCommandResultSupplier, IProductHelperSupplier, ISingularSupplier, Runnable {
@Getter @Mixin private OutputHelperMixins.WaitFor outputHelper;
@Mixin private WaitHelperControlOptions controlOptions;
@Mixin private WaitHelperWaitOptions waitOptions;
@Mixin private WaitHelperControlPropertiesMixin controlProperties;
@Mixin private WaitHelperWaitTypeMixin waitTypeSupplier;
@Mixin StandardWaitHelperProgressMonitorMixin progressMonitorMixin;

@Override
Expand All @@ -49,10 +49,11 @@ public void run() {
private void wait(UnirestInstance unirest) {
configure(
WaitHelper.builder()
.controlProperties(controlOptions)
.controlProperties(controlProperties)
.waitType(waitTypeSupplier.getWaitType())
.progressMonitor(progressMonitorMixin.create(false))
.onFinish(WaitHelper::recordsWithActionAsArrayNode, outputHelper::write)
).build().wait(unirest, waitOptions);
).build().wait(unirest);
}

protected abstract WaitHelperBuilder configure(WaitHelperBuilder builder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import lombok.Getter;
import picocli.CommandLine.Option;

public class WaitHelperControlOptions implements IWaitHelperControlProperties {
public class WaitHelperControlPropertiesMixin implements IWaitHelperControlProperties {
@Option(names= {"--on-unknown-state-requested"}, defaultValue = "fail")
@Getter private WaitUnknownStateRequestedAction onUnknownStateRequested;
@Option(names= {"--on-failure-state"}, defaultValue = "fail")
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*******************************************************************************
* Copyright 2021, 2023 Open Text.
*
* The only warranties for products and services of Open Text
* and its affiliates and licensors ("Open Text") are as may
* be set forth in the express warranty statements accompanying
* such products and services. Nothing herein should be construed
* as constituting an additional warranty. Open Text shall not be
* liable for technical or editorial errors or omissions contained
* herein. The information contained herein is subject to change
* without notice.
*******************************************************************************/
package com.fortify.cli.common.rest.cli.mixin;

import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.fortify.cli.common.rest.cli.mixin.WaitHelperWaitTypeMixin.AnyOrAllTypeConverter.AnyOrAllIterable;
import com.fortify.cli.common.rest.wait.WaitType;
import com.fortify.cli.common.rest.wait.WaitType.AnyOrAll;
import com.fortify.cli.common.rest.wait.WaitType.LoopType;

import lombok.Getter;
import picocli.CommandLine.ArgGroup;
import picocli.CommandLine.ITypeConverter;
import picocli.CommandLine.Option;

public final class WaitHelperWaitTypeMixin {
@Getter @ArgGroup(exclusive = true, multiplicity = "0..1")
private WaitHelperWaitTypeArgGroup waitTypeArgGroup;

public final WaitType getWaitType() {
if ( waitTypeArgGroup==null ) {
return new WaitType(LoopType.Until, AnyOrAll.all_match);
} else if ( waitTypeArgGroup.untilAnyOrAll!=null ) {
return new WaitType(LoopType.Until, waitTypeArgGroup.untilAnyOrAll);
} else {
return new WaitType(LoopType.While, waitTypeArgGroup.whileAnyOrAll);
}
}

private static final class WaitHelperWaitTypeArgGroup {
@Option(names = {"--until", "-u"}, required = true, paramLabel="any-match|all-match", converter = AnyOrAllTypeConverter.class, completionCandidates = AnyOrAllIterable.class)
@Getter private AnyOrAll untilAnyOrAll;
@Option(names = {"--while", "-w"}, required = true, paramLabel="any-match|all-match", converter = AnyOrAllTypeConverter.class, completionCandidates = AnyOrAllIterable.class)
@Getter private AnyOrAll whileAnyOrAll;
}

public static final class AnyOrAllTypeConverter implements ITypeConverter<AnyOrAll> {
@Override
public AnyOrAll convert(String value) throws Exception {
return AnyOrAll.valueOf(value.replace('-', '_'));
}

public static final class AnyOrAllIterable extends ArrayList<String> {
private static final long serialVersionUID = 1L;
public AnyOrAllIterable() {
super(Stream.of(AnyOrAll.values())
.map(Enum::name)
.map(s->s.replace('_', '-'))
.collect(Collectors.toList()));
}
}
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fortify.cli.common.json.JsonHelper;
import com.fortify.cli.common.output.transform.IActionCommandResultSupplier;
import com.fortify.cli.common.rest.wait.WaitType.AnyOrAll;
import com.fortify.cli.common.rest.wait.WaitType.LoopType;
import com.fortify.cli.common.util.DateTimePeriodHelper;
import com.fortify.cli.common.util.DateTimePeriodHelper.Period;
import com.fortify.cli.common.util.StringUtils;

import kong.unirest.UnirestInstance;
import lombok.Builder;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Builder
public class WaitHelper {
Expand All @@ -46,7 +46,7 @@ public class WaitHelper {
private final Function<JsonNode, JsonNode> recordTransformer;
private final String[] knownStates;
private final String[] failureStates;
private final String[] defaultCompleteStates;
private final Set<String> matchStates;
@Builder.Default private final WaitUnknownStateRequestedAction onUnknownStateRequested = WaitUnknownStateRequestedAction.fail;
@Builder.Default private final WaitUnknownOrFailureStateAction onFailureState = WaitUnknownOrFailureStateAction.fail;
@Builder.Default private final WaitUnknownOrFailureStateAction onUnknownState = WaitUnknownOrFailureStateAction.fail;
Expand All @@ -55,6 +55,7 @@ public class WaitHelper {
private final String timeoutPeriod;
private final IWaitHelperProgressMonitor progressMonitor;
private final Consumer<Map<ObjectNode, WaitStatus>> onFinish;
private final WaitType waitType;
@Getter private final Map<ObjectNode, WaitStatus> result = new LinkedHashMap<>();

public static final ArrayNode plainRecordsAsArrayNode(Map<ObjectNode, WaitStatus> recordsWithWaitStatus) {
Expand All @@ -67,56 +68,11 @@ public static final ArrayNode recordsWithActionAsArrayNode(Map<ObjectNode, WaitS
.collect(JsonHelper.arrayNodeCollector());
}

public final WaitHelper wait(UnirestInstance unirest, IWaitHelperWaitDefinitionSupplier waitDefinitionSupplier) {
return wait(unirest, waitDefinitionSupplier.getWaitDefinition());
}

public final WaitHelper wait(UnirestInstance unirest, IWaitHelperWaitDefinition waitDefinition) {
return waitUntilAll(unirest, waitDefinition.getUntilAll())
.waitUntilAny(unirest, waitDefinition.getUntilAny())
.waitWhileAll(unirest, waitDefinition.getWhileAll())
.waitWhileAny(unirest, waitDefinition.getWhileAny())
.waitComplete(unirest);
}

public final WaitHelper waitUntilAll(UnirestInstance unirest, String untilStates) {
if ( StringUtils.isNotBlank(untilStates) ) {
wait(unirest, new StateEvaluator(untilStates, EvaluatorType.Until), AnyOrAll.ALL);
}
return this;
}

public final WaitHelper waitUntilAny(UnirestInstance unirest, String untilStates) {
if ( StringUtils.isNotBlank(untilStates) ) {
wait(unirest, new StateEvaluator(untilStates, EvaluatorType.Until), AnyOrAll.ANY);
}
public final WaitHelper wait(UnirestInstance unirest) {
wait(unirest, new StateEvaluator(matchStates, waitType.getLoopType()), waitType.getAnyOrAll());
return this;
}

public final WaitHelper waitWhileAll(UnirestInstance unirest, String whileStates) {
if ( StringUtils.isNotBlank(whileStates) ) {
wait(unirest, new StateEvaluator(whileStates, EvaluatorType.While), AnyOrAll.ALL);
}
return this;
}

public final WaitHelper waitWhileAny(UnirestInstance unirest, String whileStates) {
if ( StringUtils.isNotBlank(whileStates) ) {
wait(unirest, new StateEvaluator(whileStates, EvaluatorType.While), AnyOrAll.ALL);
}
return this;
}

public final WaitHelper waitComplete(UnirestInstance unirest) {
if ( result.isEmpty() ) {
if ( defaultCompleteStates==null || defaultCompleteStates.length==0 ) {
throw new IllegalArgumentException("One of --until* or --while* must be provided");
}
wait(unirest, new StateEvaluator(String.join("|", defaultCompleteStates), EvaluatorType.Until), AnyOrAll.ALL);
}
return this;
}

private final void wait(UnirestInstance unirest, StateEvaluator evaluator, AnyOrAll anyOrAll) {
if ( currentState==null ) {
throw new RuntimeException("No currentState function or currentStateProperty set");
Expand Down Expand Up @@ -172,8 +128,8 @@ private final boolean continueWait(Map<ObjectNode, WaitStatus> waitStatuses, Any
return false;
}
switch (anyOrAll) {
case ANY: return !waitStatuses.containsValue(WaitStatus.WAIT_COMPLETE);
case ALL: return !waitStatuses.values().stream().allMatch(WaitStatus.WAIT_COMPLETE::equals);
case any_match: return !waitStatuses.containsValue(WaitStatus.WAIT_COMPLETE);
case all_match: return !waitStatuses.values().stream().allMatch(WaitStatus.WAIT_COMPLETE::equals);
default: throw new RuntimeException("This exception shouldn't occur; please submit a bug");
}
}
Expand Down Expand Up @@ -224,34 +180,17 @@ public static enum WaitStatus {
WAITING, WAIT_COMPLETE, UNKNOWN_STATE_DETECTED, FAILURE_STATE_DETECTED, TIMEOUT
}

private static enum AnyOrAll {
ANY, ALL
}

@RequiredArgsConstructor
private static enum EvaluatorType {
Until(false),
While(true);

private final boolean waitIfMatching;

public boolean isWaiting(Set<String> statesToMatch, String currentState) {
return waitIfMatching == matches(statesToMatch, currentState);
}

private static boolean matches(Set<String> statesToMatch, String currentState) {
return statesToMatch.contains(currentState);
}
}

private final class StateEvaluator {
private final Set<String> statesSet;
private final Set<String> knownStatesSet;
private final Set<String> failureStatesSet;
private final EvaluatorType evaluatorType;
private final LoopType evaluatorType;

public StateEvaluator(String statesString, EvaluatorType evaluatorType) {
this.statesSet = Set.of(statesString.split("\\|"));
public StateEvaluator(Set<String> statesSet, LoopType evaluatorType) {
this.statesSet = statesSet;
if ( statesSet==null || statesSet.isEmpty() ) {
throw new IllegalStateException("No states to be matched have been specified");
}
this.evaluatorType = evaluatorType;
this.knownStatesSet = knownStates==null ? null : new HashSet<>(Set.of(knownStates));
if ( this.knownStatesSet!=null ) {
Expand Down Expand Up @@ -328,11 +267,6 @@ public WaitHelperBuilder knownStates(String... knownStates) {
return this;
}

public WaitHelperBuilder defaultCompleteStates(String... defaultCompleteStates) {
this.defaultCompleteStates = defaultCompleteStates;
return this;
}

public <T> WaitHelperBuilder onFinish(FunctionAndThenConsumer<Map<ObjectNode, WaitStatus>, T> converter, Consumer<T> consumer) {
this.onFinish = converter.andThen(consumer);
return this;
Expand Down
Loading

0 comments on commit 8826407

Please sign in to comment.