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

commit 921d09e4202dbc3dee8d2e81d3706c475e75a27c
Author: Duncan Grant <[email protected]>
AuthorDate: Fri Jun 30 11:44:20 2023 +0100

    Allow on fire in workflow expressions
    
    When calling attributeWhenReady using workflow syntax we should
    not abort when the entity is on fire.  This is different from what
    we do using DSL expressions.
---
 .../camp/brooklyn/WorkflowExpressionsYamlTest.java | 60 ++++++++++++++++++++--
 .../core/sensor/DependentConfiguration.java        | 16 +++++-
 .../brooklyn/util/core/text/TemplateProcessor.java |  2 +-
 3 files changed, 72 insertions(+), 6 deletions(-)

diff --git 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowExpressionsYamlTest.java
 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowExpressionsYamlTest.java
index d0fb7d02e2..3036d535b1 100644
--- 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowExpressionsYamlTest.java
+++ 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowExpressionsYamlTest.java
@@ -22,23 +22,21 @@ import com.google.common.collect.Iterables;
 import com.google.common.reflect.TypeToken;
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.resolve.jackson.BeanWithTypeUtils;
 import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.workflow.WorkflowBasicTest;
 import org.apache.brooklyn.core.workflow.WorkflowExecutionContext;
 import org.apache.brooklyn.core.workflow.steps.flow.LogWorkflowStep;
-import org.apache.brooklyn.entity.stock.BasicApplication;
 import org.apache.brooklyn.entity.stock.BasicEntity;
 import org.apache.brooklyn.entity.stock.BasicEntityImpl;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.ClassLogWatcher;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.core.internal.TypeCoercionsTest;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
@@ -50,6 +48,7 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 
 public class WorkflowExpressionsYamlTest extends AbstractYamlTest {
@@ -82,6 +81,18 @@ public class WorkflowExpressionsYamlTest extends 
AbstractYamlTest {
         }
     }
 
+    private Entity createEntity() throws Exception {
+        Entity app = createAndStartApplication(
+                "services:",
+                "- type: " + BasicEntity.class.getName());
+        waitForApplicationTasks(app);
+
+        // Deploy the blueprint.
+        Entity entity = lastEntity = 
Iterables.getOnlyElement(app.getChildren());
+        synchronized (this) { this.notifyAll(); }
+        return entity;
+    }
+
     private Entity createEntityWithWorkflowEffector(String ...stepLines) 
throws Exception {
         // Declare workflow in a blueprint, add various log steps.
         Entity app = createAndStartApplication(
@@ -214,6 +225,47 @@ public class WorkflowExpressionsYamlTest extends 
AbstractYamlTest {
         }
     }
 
+    @Test
+    public void testWorkflowExpressionAllowsOnFire() throws Exception {
+        Entity entity = createEntity();
+        WorkflowExecutionContext workflow = invocationWorkflowOnLastEntity(
+                "    - step: transform ${entity.attributeWhenReady.foo} | wait 
| set foo_in_workflow",
+                "      timeout: 4s",
+                "    - step: set-sensor new-foo = ${foo_in_workflow}"
+                );
+
+        Time.sleep(Duration.ONE_SECOND);
+        Asserts.assertFalse(workflow.getTask(false).get().isDone());
+
+        waitForLastEntity().sensors().set(Attributes.SERVICE_STATE_ACTUAL, 
Lifecycle.ON_FIRE);
+        Time.sleep(Duration.of(2, TimeUnit.SECONDS));
+        waitForLastEntity().sensors().set(Sensors.newIntegerSensor("foo"), 10);
+
+        workflow.getTask(false).get().blockUntilEnded(Duration.TEN_SECONDS);
+        Asserts.assertFalse(workflow.getTask(true).get().isError());
+        Integer fooInWorkflow = 
entity.sensors().get(Sensors.newIntegerSensor("new-foo"));
+        Asserts.assertEquals((Integer) 10, fooInWorkflow);
+    }
+
+    @Test
+    public void testDSLExpressionAbortWhenOnFire() throws Exception {
+        createEntity();
+        WorkflowExecutionContext workflow = invocationWorkflowOnLastEntity(
+                "    - step: transform $brooklyn:attributeWhenReady(\"foo\") | 
wait | set foo_in_workflow",
+                "      timeout: 3s"
+        );
+
+        Time.sleep(Duration.ONE_SECOND);
+        Asserts.assertFalse(workflow.getTask(false).get().isDone());
+
+        waitForLastEntity().sensors().set(Attributes.SERVICE_STATE_ACTUAL, 
Lifecycle.ON_FIRE);
+        Time.sleep(Duration.of(2, TimeUnit.SECONDS));
+        waitForLastEntity().sensors().set(Sensors.newIntegerSensor("foo"), 10);
+
+        workflow.getTask(false).get().blockUntilEnded(Duration.TEN_SECONDS);
+        Asserts.assertTrue(workflow.getTask(true).get().isError());
+    }
+
     @Test
     public void testWorkflowExpressionMixingBrooklynDslAndExpressions() throws 
Exception {
         createEntityWithWorkflowEffector("- s: let x = $brooklyn:self()", "  
output: ${x}");
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
 
b/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
index 731a0eff25..351677bcb0 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
@@ -121,7 +121,11 @@ public class DependentConfiguration {
     public static <T> Task<T> attributeWhenReady(Entity source, 
AttributeSensor<T> sensor) {
         return attributeWhenReady(source, sensor, 
JavaGroovyEquivalents.groovyTruthPredicate());
     }
-    
+
+    public static <T> Task<T> attributeWhenReadyAllowingOnFire(Entity source, 
AttributeSensor<T> sensor) {
+        return attributeWhenReadyAllowingOnFire(source, sensor, 
JavaGroovyEquivalents.groovyTruthPredicate());
+    }
+
     /**
      * @deprecated since 0.11.0; explicit groovy utilities/support will be 
deleted.
      */
@@ -141,6 +145,16 @@ public class DependentConfiguration {
 
     }
 
+    /** returns an unsubmitted {@link Task} which blocks until the given 
sensor on the given source entity gives a value that satisfies ready, then 
returns that value;
+     * particular useful in Entity configuration where config will block until 
Tasks have a value
+     */
+    public static <T> Task<T> attributeWhenReadyAllowingOnFire(final Entity 
source, final AttributeSensor<T> sensor, final Predicate<? super T> ready) {
+        Builder<T, T> builder = 
builder().attributeWhenReadyAllowingOnFire(source, 
sensor).timeoutIfStoppingOrDestroyed(Duration.ONE_MINUTE);
+        if (ready != null) builder.readiness(ready);
+        return builder.build();
+
+    }
+
     /**
      * @deprecated since 0.11.0; explicit groovy utilities/support will be 
deleted.
      */
diff --git 
a/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java 
b/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
index 815a9642c7..771fe150fb 100644
--- 
a/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
+++ 
b/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
@@ -626,7 +626,7 @@ public class TemplateProcessor {
             try {
                 result =
                         mode == SensorResolutionMode.ATTRIBUTE_WHEN_READY ?
-                                
((EntityInternal)entity).getExecutionContext().get( 
DependentConfiguration.attributeWhenReady(entity,
+                                
((EntityInternal)entity).getExecutionContext().get( 
DependentConfiguration.attributeWhenReadyAllowingOnFire(entity,
                                     Sensors.builder(Object.class, 
key).persistence(AttributeSensor.SensorPersistenceMode.NONE).build()))
                         : mode == SensorResolutionMode.ATTRIBUTE_VALUE ?
                                 entity.sensors().get( 
Sensors.newSensor(Object.class, key) )

Reply via email to