This is an automated email from the ASF dual-hosted git repository.
heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
The following commit(s) were added to refs/heads/master by this push:
new cc86e2f4dd transform syntax improved
cc86e2f4dd is described below
commit cc86e2f4dde74c5ae52ca6373243a0723903896c
Author: Alex Heneveld <[email protected]>
AuthorDate: Tue Jun 20 13:32:19 2023 +0100
transform syntax improved
add explicit "variable" or "value"; and only the former will update in
place.
disallow (for now) `transform ambiguous_thing | some_transform` --
requiring `ambiguous_thing` to be an expression
---
.../brooklyn/core/workflow/ShorthandProcessor.java | 8 ++
.../workflow/WorkflowExpressionResolution.java | 39 ++++--
.../core/workflow/WorkflowStepDefinition.java | 12 +-
.../steps/appmodel/UpdateChildrenWorkflowStep.java | 4 +-
.../steps/variables/SetVariableWorkflowStep.java | 4 +-
.../variables/TransformVariableWorkflowStep.java | 142 ++++++++++++++++-----
.../core/workflow/ShorthandProcessorTest.java | 2 +
.../brooklyn/core/workflow/WorkflowBasicTest.java | 29 +++++
.../core/workflow/WorkflowMapAndListTest.java | 2 -
.../brooklyn/core/workflow/WorkflowSizeTest.java | 9 +-
.../core/workflow/WorkflowTransformTest.java | 79 ++++++++++--
11 files changed, 261 insertions(+), 69 deletions(-)
diff --git
a/core/src/main/java/org/apache/brooklyn/core/workflow/ShorthandProcessor.java
b/core/src/main/java/org/apache/brooklyn/core/workflow/ShorthandProcessor.java
index 0e81dfc966..32ba2f835c 100644
---
a/core/src/main/java/org/apache/brooklyn/core/workflow/ShorthandProcessor.java
+++
b/core/src/main/java/org/apache/brooklyn/core/workflow/ShorthandProcessor.java
@@ -46,6 +46,14 @@ import java.util.stream.Collectors;
* "LITERAL" - to expect a literal expression. this must include the quotation
marks and should include spaces if spaces are required.
* [ TOKEN ] - to indicate TOKEN is optional, where TOKEN is one of the above
sections. parsing is attempted first with it, then without it.
* [ ?${VAR} TOKEN ] - as `[ TOKEN ]` but VAR is set true or false depending
whether this optional section was matched.
+ *
+ * Would be nice to support A | B (exclusive or) for A or B but not both
(where A might contain a literal for disambiguation),
+ * and ( X ) for X required but grouped (for use with | (exclusive or) where
one option is required).
+ * Would also be nice to support any order, which could be ( A & B ) to allow
A B or B A.
+ *
+ * But for now we've made do without it, with some compromises:
+ * * keywords must follow the order indicated
+ * * exclusive alternatives are disallowed by code subsequently or checked
separately (eg Transform)
*/
public class ShorthandProcessor {
diff --git
a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExpressionResolution.java
b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExpressionResolution.java
index a18b78d8bd..76bc842329 100644
---
a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExpressionResolution.java
+++
b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExpressionResolution.java
@@ -389,25 +389,42 @@ public class WorkflowExpressionResolution {
/** does not use templates */
public <T> T resolveCoercingOnly(Object expression, TypeToken<T> type) {
if (expression==null) return null;
+ boolean triedCoercion = false;
+ List<Exception> exceptions = MutableList.of();
+ if (expression instanceof String) {
+ try {
+ // prefer simple coercion if it's a string coming in
+ return TypeCoercions.coerce(expression, type);
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ exceptions.add(e);
+ triedCoercion = true;
+ }
+ }
+
if (Jsonya.isJsonPrimitiveDeep(expression) && !(expression instanceof
Set)) {
try {
- // only try yaml coercion, as values are normally set from
yaml and will be raw at this stage (but not if they are from a DSL)
- // (might be better to always to TC.coerce)
+ // next try yaml coercion for anything complex, as values are
normally set from yaml and will be raw at this stage (but not if they are from
a DSL)
return
BeanWithTypeUtils.convert(context.getManagementContext(), expression, type,
true,
RegisteredTypes.getClassLoadingContext(context.getEntity()), true /* needed for
wrapped resolved holders */);
} catch (Exception e) {
Exceptions.propagateIfFatal(e);
- try {
- // fallback to simple coercion
- return TypeCoercions.coerce(expression, type);
- } catch (Exception e2) {
- Exceptions.propagateIfFatal(e2);
- throw Exceptions.propagate(e);
- }
+ exceptions.add(e);
}
- } else {
- return TypeCoercions.coerce(expression, type);
}
+
+ if (!triedCoercion) {
+ try {
+ // fallback to simple coercion
+ return TypeCoercions.coerce(expression, type);
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ exceptions.add(e);
+ triedCoercion = true;
+ }
+ }
+
+ throw Exceptions.propagate(exceptions.iterator().next());
}
static class WorkflowVariableResolutionStackEntry {
diff --git
a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepDefinition.java
b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepDefinition.java
index f6a2cdc54a..f51d962208 100644
---
a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepDefinition.java
+++
b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepDefinition.java
@@ -159,16 +159,18 @@ public abstract class WorkflowStepDefinition {
abstract public void populateFromShorthand(String value);
protected void populateFromShorthandTemplate(String template, String
value) {
- populateFromShorthandTemplate(template, value, false, true);
+ populateFromShorthandTemplate(template, value, false, true, true);
}
- protected Maybe<Map<String, Object>> populateFromShorthandTemplate(String
template, String value, boolean finalMatchRaw, boolean failOnMismatch) {
+ protected Map<String, Object> populateFromShorthandTemplate(String
template, String value, boolean finalMatchRaw, boolean failOnMismatch, boolean
failOnError) {
Maybe<Map<String, Object>> result = new
ShorthandProcessor(template).withFinalMatchRaw(finalMatchRaw).withFailOnMismatch(failOnMismatch).process(value);
- if (result.isAbsent())
- throw new IllegalArgumentException("Invalid shorthand expression:
'" + value + "'", Maybe.Absent.getException(result));
+ if (result.isAbsent()) {
+ if (failOnError) throw new IllegalArgumentException("Invalid
shorthand expression: '" + value + "'", Maybe.Absent.getException(result));
+ return null;
+ }
input.putAll((Map<? extends String, ?>)
CollectionMerger.builder().build().merge(input, result.get()));
- return result;
+ return result.get();
}
final Task<?> newTask(WorkflowStepInstanceExecutionContext context) {
diff --git
a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/appmodel/UpdateChildrenWorkflowStep.java
b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/appmodel/UpdateChildrenWorkflowStep.java
index a62ef63f66..777b0da50e 100644
---
a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/appmodel/UpdateChildrenWorkflowStep.java
+++
b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/appmodel/UpdateChildrenWorkflowStep.java
@@ -274,8 +274,8 @@ public class UpdateChildrenWorkflowStep extends
WorkflowStepDefinition implement
List matches =
runOrResumeSubWorkflowForPhaseOrReturnPreviousIfCompleted(context,
instructionsForResuming, subworkflowTargetForResuming,
"Matching items against children", stepState.matchCheck,
MATCH_CHECK_WORKFLOW,
() -> new CustomWorkflowStep(MutableList.of(
- "transform identifier_expression | resolve_expression
| set id",
- MutableMap.of("step", "fail message
identifier_expression should be a non-static expression including an
interpolated reference to item",
+ "transform ${identifier_expression} |
resolve_expression | set id",
+ MutableMap.of("step", "fail message
identifier_expression should be a non-static expression including an
interpolated reference to item, instead got ${identifier_expression}",
"condition", MutableMap.of("target",
"${identifier_expression}", "equals", "${id}")),
"let child_or_id = ${parent.children[id]} ?? ${id}",
"transform child_tostring = ${child_or_id} |
to_string",
diff --git
a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/variables/SetVariableWorkflowStep.java
b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/variables/SetVariableWorkflowStep.java
index fb2d2ebfa1..9afebbd3df 100644
---
a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/variables/SetVariableWorkflowStep.java
+++
b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/variables/SetVariableWorkflowStep.java
@@ -73,8 +73,8 @@ public class SetVariableWorkflowStep extends
WorkflowStepDefinition {
@Override
public void populateFromShorthand(String expression) {
- Maybe<Map<String, Object>> newInput =
populateFromShorthandTemplate(SHORTHAND, expression, true, true);
- if (newInput.isPresentAndNonNull() &&
newInput.get().get(VALUE.getName())!=null &&
input.get(INTERPOLATION_MODE.getName())==null) {
+ Map<String, Object> newInput =
populateFromShorthandTemplate(SHORTHAND, expression, true, true, true);
+ if (newInput.get(VALUE.getName())!=null &&
input.get(INTERPOLATION_MODE.getName())==null) {
setInput(INTERPOLATION_MODE, InterpolationMode.WORDS);
}
}
diff --git
a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/variables/TransformVariableWorkflowStep.java
b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/variables/TransformVariableWorkflowStep.java
index e014bb661c..86bbb0f58a 100644
---
a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/variables/TransformVariableWorkflowStep.java
+++
b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/variables/TransformVariableWorkflowStep.java
@@ -31,8 +31,10 @@ import
org.apache.brooklyn.core.workflow.WorkflowExecutionContext;
import org.apache.brooklyn.core.workflow.WorkflowExpressionResolution;
import org.apache.brooklyn.core.workflow.WorkflowStepDefinition;
import org.apache.brooklyn.core.workflow.WorkflowStepInstanceExecutionContext;
-import org.apache.brooklyn.util.collections.*;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.text.QuotedStringTokenizer;
import org.apache.brooklyn.util.text.Strings;
@@ -41,7 +43,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
@@ -54,19 +59,38 @@ public class TransformVariableWorkflowStep extends
WorkflowStepDefinition {
private static final Logger log =
LoggerFactory.getLogger(TransformVariableWorkflowStep.class);
- public static final String SHORTHAND =
- "[ [ [ ${variable.type} ] [ ?${value_is_initial} \"value\" ]
${variable.name} " +
- "[ [ \"=\" ${value...} ] \"|\" ${transform...} ] ] ]";
+ public static final String[] SHORTHAND_OPTIONS = {
+ "[ ${variable.type} ] " +
+ "\"variable\" ${variable.name} " +
+// "[ \"=\" ${value...} ] " + // no point in allowing this
+ "[ \"|\" ${transform...} ]",
+
+ "[ ${variable.type} ] " +
+ "\"value\" ${value} " +
+ "[ \"|\" ${transform...} ]",
+
+ "[ ${variable.type} ] " +
+ "${vv_auto} " +
+ "[ \"=\" ${value...} ] " +
+ "[ \"|\" ${transform...} ]",
+ };
public static final ConfigKey<TypedValueToSet> VARIABLE =
ConfigKeys.newConfigKey(TypedValueToSet.class, "variable");
- public static final ConfigKey<Boolean> VALUE_IS_INITIAL =
ConfigKeys.newConfigKey(Boolean.class, "value_is_initial");
public static final ConfigKey<Object> VALUE =
ConfigKeys.newConfigKey(Object.class, "value");
+ public static final ConfigKey<Object> VV_AUTO =
ConfigKeys.newConfigKey(Object.class, "vv_auto");
+
public static final ConfigKey<Object> TRANSFORM =
ConfigKeys.newConfigKey(Object.class, "transform");
@Override
public void populateFromShorthand(String expression) {
- populateFromShorthandTemplate(SHORTHAND, expression, true, true);
+ Map<String, Object> match = null;
+ for (int i=0; i<SHORTHAND_OPTIONS.length && match==null; i++)
+ match = populateFromShorthandTemplate(SHORTHAND_OPTIONS[i],
expression, false, true, false);
+
+ if (match==null && Strings.isNonBlank(expression)) {
+ throw new IllegalArgumentException("Invalid shorthand expression
for transform: '" + expression + "'");
+ }
}
@Override
@@ -80,7 +104,6 @@ public class TransformVariableWorkflowStep extends
WorkflowStepDefinition {
@Override
protected Object doTaskBody(WorkflowStepInstanceExecutionContext context) {
TypedValueToSet variable = context.getInput(VARIABLE);
- String name;
Object transformO = context.getInputRaw(TRANSFORM.getName());
if (!(transformO instanceof Iterable)) transformO =
MutableList.of(transformO);
@@ -90,36 +113,83 @@ public class TransformVariableWorkflowStep extends
WorkflowStepDefinition {
else throw new IllegalArgumentException("Argument to transform
should be a string or list of strings, not: "+t);
}
- Object v;
- if (input.containsKey(VALUE.getName())) {
- name = variable==null ? null :
context.resolve(WorkflowExpressionResolution.WorkflowExpressionStage.STEP_INPUT,
variable.name, String.class);
-
- if (!Strings.isBlank(name) &&
Boolean.TRUE.equals(context.getInput(VALUE_IS_INITIAL))) {
- // allowed with no var name, we use the value as if "value"
was specified, or with a var name, the var will be set
- // but not allowed if "value" keyword was supplied because
that means the var name is to be treated as the value
- throw new IllegalArgumentException("Cannot specifiy
value_is_initial (keyword \"value\") with an = value");
+ String varName = null;
+ Object vv_auto = input.get(VV_AUTO.getName());
+ boolean variableNameSpecified = variable != null &&
Strings.isNonBlank(variable.name);
+
+ Object valueExpressionToTransform = null;
+
+ boolean setVariableAtEnd = variableNameSpecified;
+ Boolean typeCoercionAtStart = null;
+
+ if (Strings.isNonBlank((String)vv_auto)) {
+ boolean isVariable = input.containsKey(VALUE.getName());
+ boolean isValue = variableNameSpecified;
+
+ if (!isVariable && !isValue) {
+ isValue = true;
+ // in future, just do the line above
+ // ...
+ // but for now we need to exclude it if it matches a workflow
variable because that could be legacy syntax
+ boolean isDisallowedUndecoratedVariable = false;
+ try {
+ Object vvAutoResolved =
context.resolve(WorkflowExpressionResolution.WorkflowExpressionStage.STEP_INPUT,
"${" + vv_auto + "}", Object.class);
+ isDisallowedUndecoratedVariable = true;
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ // otherwise normal, it does not match a variable name, so
treat it as the value
+ }
+ if (isDisallowedUndecoratedVariable)
+ throw new IllegalArgumentException("Legacy transform
syntax `transform var_name | ...` disallowed (" + vv_auto + "); use
'${"+vv_auto+"'}' if you don't want to update it or insert the keyword
'variable' if you do");
}
- v = input.get(VALUE.getName());
- if (variable!=null && Strings.isNonBlank(variable.type))
transforms.add("type "+variable.type);
+ if (isVariable) {
+ if (isValue) throw new IllegalArgumentException("Legacy
transform identified as both value and variable");
- } else {
- if (variable==null || Strings.isBlank(variable.name)) throw new
IllegalArgumentException("Variable name is required");
+ varName = (String) vv_auto;
+ setVariableAtEnd = true;
+ typeCoercionAtStart = false;
- v = "${" + variable.name + "}";
- if (Boolean.TRUE.equals(context.getInput(VALUE_IS_INITIAL)) ||
"value".equals(variable.type)) {
- // special keyword to treat name as a literal expression
- v = variable.name;
- }
- if (Strings.isNonBlank(variable.type)) {
- if (Boolean.TRUE.equals(context.getInput(VALUE_IS_INITIAL)) ||
!"value".equals(variable.type)) {
- transforms.add(0, "type " + variable.type);
- }
+ } else {
+ if (!isValue) throw new IllegalArgumentException("Legacy
transform cannot identify as value or variable");
+
+ valueExpressionToTransform = vv_auto;
+ typeCoercionAtStart = !variableNameSpecified;
}
- name = null;
+ }
+
+ if (variableNameSpecified) {
+ if (varName!=null) throw new IllegalStateException("Variable name
specified twice"); //shouldn't happen
+ varName = variable.name;
+ setVariableAtEnd = true;
+ }
+
+ if (valueExpressionToTransform==null) {
+ // value not set from auto; check if specified elsewhere
+ valueExpressionToTransform = input.get(VALUE.getName());
+
+ if (typeCoercionAtStart==null && valueExpressionToTransform!=null)
typeCoercionAtStart = !variableNameSpecified;
+ }
+ if (valueExpressionToTransform==null) {
+ if (!variableNameSpecified) throw new
IllegalArgumentException("Transform needs a variable or value to transform");
+
+ valueExpressionToTransform = "${"+variable.name+"}";
+ if (typeCoercionAtStart!=null) throw new
IllegalStateException("Unclear whether to do type coercion; should be unset");
// shouldn't come here
+ typeCoercionAtStart = true;
+ }
+
+ if (typeCoercionAtStart==null) {
+ throw new IllegalStateException("Unclear whether to do type
coercion; should be set"); // shouldn't come here
+ }
+
+ if (variable!=null && Strings.isNonBlank(variable.type)) {
+ // if type is specified with a variable used to start the
transform, we coerce to that type at the start and at the end
+ if (typeCoercionAtStart) transforms.add(0, "type " +
variable.type);
+ if (setVariableAtEnd) transforms.add("type " + variable.type);
}
boolean isResolved = false;
+ Object v = valueExpressionToTransform;
for (String t: transforms) {
WorkflowTransformWithContext tt = getTransform(context, t);
@@ -129,7 +199,7 @@ public class TransformVariableWorkflowStep extends
WorkflowStepDefinition {
v =
context.resolve(WorkflowExpressionResolution.WorkflowExpressionStage.STEP_RUNNING,
v, TypeToken.of(Object.class));
isResolved = true;
} else if (!req && isResolved) {
- throw new IllegalArgumentException("Transform '" + t + "' must
be first as it requires unresolved input");
+ throw new IllegalArgumentException("Transform '" + t + "' must
be first or follow a resolve_expression transform as it requires unresolved
input");
} else {
// requirement matches resolution status, both done, or both
not
}
@@ -145,9 +215,13 @@ public class TransformVariableWorkflowStep extends
WorkflowStepDefinition {
isResolved = true;
}
- if (name!=null) {
- Object oldValue = setWorkflowScratchVariableDotSeparated(context,
name, v);
- // these are easily inferred from workflow vars
+ if (setVariableAtEnd) {
+ if (varName==null) throw new IllegalStateException("Variable name
not specified when setting variable"); // shouldn't happen
+
+ setWorkflowScratchVariableDotSeparated(context, varName, v);
+ // easily inferred from workflow vars, now that updates are stored
separately
+// Object oldValue =
+// <above> setWorkflowScratchVariableDotSeparated(context,
varName, v);
// context.noteOtherMetadata("Value set", v);
// if (oldValue != null) context.noteOtherMetadata("Previous
value", oldValue);
diff --git
a/core/src/test/java/org/apache/brooklyn/core/workflow/ShorthandProcessorTest.java
b/core/src/test/java/org/apache/brooklyn/core/workflow/ShorthandProcessorTest.java
index 3b32b00fc8..bb52a32ade 100644
---
a/core/src/test/java/org/apache/brooklyn/core/workflow/ShorthandProcessorTest.java
+++
b/core/src/test/java/org/apache/brooklyn/core/workflow/ShorthandProcessorTest.java
@@ -19,6 +19,7 @@
package org.apache.brooklyn.core.workflow;
import org.apache.brooklyn.core.test.BrooklynMgmtUnitTestSupport;
+import
org.apache.brooklyn.core.workflow.steps.variables.TransformVariableWorkflowStep;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.util.collections.MutableMap;
import org.testng.annotations.Test;
@@ -160,4 +161,5 @@ the logic will take the one which matches the optional
word1 but as minimally as
assertShorthandOfGives("[ [ ${a} ] ${b} [ \"=\" ${c...} ] ]", "b = c",
MutableMap.of("b", "b", "c", "c"));
assertShorthandOfGives("[ [ ${a} ] ${b} [ \"=\" ${c...} ] ]", "a b =
c", MutableMap.of("a", "a", "b", "b", "c", "c"));
}
+
}
diff --git
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java
index 16e88d8d99..e8da1bf0de 100644
---
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java
+++
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java
@@ -450,4 +450,33 @@ public class WorkflowBasicTest extends
BrooklynMgmtUnitTestSupport {
));
}
}
+
+ @Test
+ public void testConditionResolvesAndExactlyOnce() {
+ loadTypes();
+ BasicApplication app =
mgmt.getEntityManager().createEntity(EntitySpec.create(BasicApplication.class));
+ WorkflowExecutionContext w1 = WorkflowBasicTest.runWorkflow(app,
Strings.lines(
+ "steps:",
+ " - step: let a = b",
+ " - step: let b = c",
+ " - step: let list result = []",
+ " - step: transform variable result | append a=b",
+ " condition:",
+ " target: ${a}",
+ " equals: b",
+ " - step: transform variable result | append a=c",
+ " condition:",
+ " target: ${a}",
+ " equals: c",
+ " - step: transform variable result | append b=c",
+ " condition:",
+ " target: ${b}",
+ " equals: c",
+ " - return ${result}"
+ ), null);
+ Asserts.assertEquals(
+ w1.getTask(false).get().getUnchecked(),
+ MutableList.of("a=b", "b=c"));
+ }
+
}
diff --git
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowMapAndListTest.java
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowMapAndListTest.java
index 03b14b9d6e..0d9616c1d9 100644
---
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowMapAndListTest.java
+++
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowMapAndListTest.java
@@ -18,7 +18,6 @@
*/
package org.apache.brooklyn.core.workflow;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.api.entity.EntitySpec;
@@ -27,7 +26,6 @@ import org.apache.brooklyn.entity.stock.BasicApplication;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
import org.testng.Assert;
import org.testng.annotations.Test;
diff --git
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowSizeTest.java
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowSizeTest.java
index ec81b25d8c..917f0c1f7b 100644
--- a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowSizeTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowSizeTest.java
@@ -70,9 +70,10 @@ public class WorkflowSizeTest extends
BrooklynMgmtUnitTestSupport {
createAppWithEffector(MutableList.of(
"let pc = ${param}",
"let map myMap = {}",
- "transform param | prepend hello-",
+ "transform ${param} | prepend hello_",
+ "transform variable param | prepend hello-",
"let myMap.a = ${param}",
- "let myMap.b = ${output}",
+ "let myMap.b = ${output}", // comes from hello_ further up
"return ${myMap}"
));
@@ -95,7 +96,7 @@ public class WorkflowSizeTest extends
BrooklynMgmtUnitTestSupport {
sizes.forEach((k,v) -> { log.info("Sensor "+k+": "+v); });
Asserts.assertThat(sizes.values().stream().reduce(0, (v0,v1)->v0+v1),
result -> result < 20*1000);
- // 100k payload now -> bumps sensor (json) size from 5k to 3MB (before
any optimization)
+ // 100k payload -> bumps sensor (json) size from 5k to 3MB (before any
optimization)
// [xml persistence is less of an issue because it will use a shared
reference]
// removing output which is identical to the previous gives minor
savings (in this test): 3380416 -> 3176074
// removing scratch at workflow which matches a step reduces further:
-> 2869522
@@ -107,7 +108,7 @@ public class WorkflowSizeTest extends
BrooklynMgmtUnitTestSupport {
app.invoke(app.getEntityType().getEffectorByName("myWorkflow").get(),
MutableMap.of("param", sampleData)).getUnchecked();
sizes = getSensorSizes();
sizes.forEach((k,v) -> { log.info("Sensor "+k+": "+v); });
- Asserts.assertThat(sizes.values().stream().reduce(0, (v0,v1)->v0+v1),
result -> result > 100*1000);
+ Asserts.assertThat(sizes.values().stream().reduce(0, (v0,v1)->v0+v1),
result -> result > 100*1000 && result < 2*1000*1000);
}
protected Map<String,Integer> getSensorSizes() {
diff --git
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowTransformTest.java
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowTransformTest.java
index 9d102cf6f6..af4746cd90 100644
---
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowTransformTest.java
+++
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowTransformTest.java
@@ -25,6 +25,7 @@ import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.api.mgmt.Task;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.test.BrooklynMgmtUnitTestSupport;
+import
org.apache.brooklyn.core.workflow.steps.variables.TransformVariableWorkflowStep;
import org.apache.brooklyn.entity.stock.BasicApplication;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.util.collections.MutableList;
@@ -74,6 +75,49 @@ public class WorkflowTransformTest extends
BrooklynMgmtUnitTestSupport {
return runWorkflowSteps(app, "transform "+args);
}
+
+ @Test
+ public void testTransformShorthand() {
+ Function<String,Map<String,Object>> parse = shorthand -> {
+ TransformVariableWorkflowStep s = new
TransformVariableWorkflowStep();
+ s.populateFromShorthand(shorthand);
+ return s.input;
+ };
+
+ Asserts.assertEquals(parse.apply("variable x"), MutableMap.of(
+ "variable", MutableMap.of("name", "x")));
+
+ Asserts.assertEquals(parse.apply("value ${x}"), MutableMap.of(
+ "value", "${x}"));
+
+ Asserts.assertEquals(parse.apply("x"), MutableMap.of(
+ "vv_auto", "x"));
+
+ Asserts.assertEquals(parse.apply("x = 1 | foo"), MutableMap.of(
+ "vv_auto", "x",
+ "value", "1",
+ "transform", "foo"));
+ Asserts.assertEquals(parse.apply("integer x = 1 | foo"), MutableMap.of(
+ "variable", MutableMap.of("type", "integer"),
+ "vv_auto", "x",
+ "value", "1",
+ "transform", "foo"));
+
+ Asserts.assertEquals(parse.apply("integer variable x | foo"),
MutableMap.of(
+ "variable", MutableMap.of("name", "x", "type", "integer"),
+ "transform", "foo"));
+ Asserts.assertEquals(parse.apply("integer value ${x} | foo"),
MutableMap.of(
+ "variable", MutableMap.of("type", "integer"),
+ "value", "${x}",
+ "transform", "foo"));
+
+ Asserts.assertFailsWith(() -> parse.apply("integer variable x = 99 |
foo"),
+ e -> Asserts.expectedFailureContainsIgnoreCase(e, "Invalid
shorthand expression for transform"));
+ Asserts.assertFailsWith(() -> parse.apply("integer value x = 99 |
foo"),
+ e -> Asserts.expectedFailureContainsIgnoreCase(e, "Invalid
shorthand expression for transform"));
+ }
+
+
@Test
public void testTransformTrim() throws Exception {
String untrimmed = "Hello, World! ";
@@ -140,7 +184,7 @@ public class WorkflowTransformTest extends
BrooklynMgmtUnitTestSupport {
" that's: okay",
" ---",
" key: value",
- "- transform s | yaml | return",
+ "- transform ${s} | yaml | return",
"- return should not come here",
""), "test").getTask(false).get().getUnchecked(),
MutableMap.of("key", "value"));
@@ -151,15 +195,31 @@ public class WorkflowTransformTest extends
BrooklynMgmtUnitTestSupport {
Asserts.assertEquals(WorkflowBasicTest.runWorkflow(app, Strings.lines(
"- step: let s",
" value: \"key: Value\"",
- "- transform s | yaml | set y",
+ "- transform ${s} | yaml | set y",
"- transform y.key2 = ${output.key} | to_upper_case",
- "- transform output.key | to_lower_case", // output
should still be the yaml map transformed from ${s}
- "- transform output | set y.key3", // output passed in
here will be 'value' from previous step
- "- transform value true | set y.key4",
- "- transform boolean value true | set y.key5",
+ "- transform ${output.key} | to_lower_case", // output
should still be the yaml map transformed from ${s}
+ "- transform ${output} | set y.key3", // output passed
in here will be 'value' from previous step
+ "- transform true | set y.key4a",
+ "- transform value true | set y.key4b",
+ "- transform boolean value true | set y.key4c",
"- return ${y}",
- ""), "test").getTask(false).get().getUnchecked(),
- MutableMap.of("key", "Value", "key2", "VALUE", "key3",
"value", "key4", "true", "key5", true));
+ ""), "test").getTask(true).get().getUnchecked(),
+ MutableMap.of("key", "Value", "key2", "VALUE", "key3",
"value", "key4a", "true", "key4b", "true", "key4c", true));
+ }
+
+ @Test
+ public void testValueTransform() {
+ Asserts.assertEquals(WorkflowBasicTest.runWorkflow(app, Strings.lines(
+ "- let map m = { a: x }",
+ "- transform value ${m} | size"
+ ), "test").getTask(true).get().getUnchecked(), 1);
+
+// "- let x = hello",
+// "- transform value ${x} | append world"),
"test").getTask(true).get().getUnchecked(), "helloworld");
+// "- let apply_result = hello",
+// "- transform value ${apply_result} | to_upper_case"
+// , "- return ${apply_result}"
+// ), "test").getTask(true).get().getUnchecked(), "HELLO");
}
@Test
@@ -168,7 +228,8 @@ public class WorkflowTransformTest extends
BrooklynMgmtUnitTestSupport {
"let a = b",
"let b = c",
"let x = \"${\" ${a} \"}\"",
- "transform x | resolve_expression | return"
+ "transform variable x | resolve_expression",
+ "return ${x}"
), "c");
Asserts.assertEquals(runWorkflowSteps(