You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2016/11/29 13:40:15 UTC

[01/13] brooklyn-server git commit: Testing override of java MapConfigKey in brooklyn.parameters

Repository: brooklyn-server
Updated Branches:
  refs/heads/master 721ced78d -> 56496fa54


Testing override of java MapConfigKey in brooklyn.parameters


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/e28c4b39
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/e28c4b39
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/e28c4b39

Branch: refs/heads/master
Commit: e28c4b3916c5e6e35892147a5e0a87f1e11e7d5f
Parents: 92ff820
Author: Aled Sage <al...@gmail.com>
Authored: Thu Nov 17 16:30:15 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 28 21:11:48 2016 +0000

----------------------------------------------------------------------
 .../camp/brooklyn/ConfigNestedYamlTest.java     |  2 +-
 .../camp/brooklyn/ConfigParametersYamlTest.java | 75 +++++++++++++++++++-
 2 files changed, 74 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e28c4b39/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigNestedYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigNestedYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigNestedYamlTest.java
index 2d6526f..699b02d 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigNestedYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigNestedYamlTest.java
@@ -87,7 +87,7 @@ public class ConfigNestedYamlTest extends AbstractYamlTest {
     @Test
     public void testCatalogParameterFromSuperYamlTypeAsSoftware() throws Exception {
         addCatalogItems( loadYaml("config-nested-test.bom") );
-        Entity ent = doTestWithBlueprint( "services: [ { type: test-map-parameter-software } ]", true);
+        Entity ent = doTestWithBlueprint( "services: [ { type: test-map-parameter-software } ]", false);
         Entities.dumpInfo(ent);
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e28c4b39/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
index 78219c6..2336030 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
@@ -140,6 +140,78 @@ public class ConfigParametersYamlTest extends AbstractYamlRebindTest {
         assertKeyEquals(newEntity, TestEntity.CONF_NAME.getName(), "myDescription", String.class, "myDefaultYamlVal", "myDefaultYamlVal");
     }
     
+    // See https://issues.apache.org/jira/browse/BROOKLYN-345, and the breakage that 
+    // fix originally caused - discussed in https://github.com/apache/brooklyn-server/pull/440.
+    //
+    // When brooklyn.parameters defines TestEntity.CONF_MAP_THING, it now means that this redefined
+    // config key is used for lookup. This now has type `BasicConfigKey<Map>` rather than 
+    // `MapConfigKey`. However, when the data was being written (via `entity.config().set(key, val)`)
+    // it was using the `MapConfigKey`. Unfortunately the `MapConfigKey` uses a different structure
+    // for storing its data (flattening out the map). So the subsequent lookup failed.
+    //
+    // There are three parts to fixing this:
+    //  1. [DONE] In `entity.config().set(key, val)`, replace `key` with the entity's own key  
+    //     (i.e. the same logic that will subsequently be used in the `get`).
+    //  2. [DONE] In `BrooklynComponentTemplateResolver.findAllFlagsAndConfigKeyValues`, respect  
+    //     the precedence of the config keys - prefer the `brooklyn.parameters` over the key defined
+    //     in the super-type (e.g. in the java class).
+    //  3. [TODO] Investigate rebind: the entity's ownConfig ends up with the "test.confMapThing.mykey=myval",
+    //     so it has populated it using the MayConfigKey structure rather than the override config key.
+    //  4. [TODO] Major overhaul of the ConfigKey name versus `SetFromFlag` alias. It is currently
+    //     confusing in when reading the config values what the precedence is because there are 
+    //     different names that are only understood by some things.
+    @Test(groups="Broken")
+    public void testConfigParameterOverridingJavaMapConfigKey() throws Exception {
+        runConfigParameterOverridingJavaMapConfigKey(true);
+    }
+    
+    @Test
+    public void testConfigParameterOverridingJavaMapConfigKeyWithoutRebindValueCheck() throws Exception {
+        // A cut-down test of what is actually working just now (so we can detect any 
+        // further regressions!)
+        runConfigParameterOverridingJavaMapConfigKey(false);
+    }
+    
+    protected void runConfigParameterOverridingJavaMapConfigKey(boolean assertReboundVal) throws Exception {
+        addCatalogItems(
+                "brooklyn.catalog:",
+                "  itemType: entity",
+                "  items:",
+                "  - id: entity-with-keys",
+                "    item:",
+                "      type: "+TestEntity.class.getName(),
+                "      brooklyn.parameters:",
+                "      - name: " + TestEntity.CONF_MAP_THING.getName(),
+                "        description: myDescription",
+                "        type: java.util.Map",
+                "      brooklyn.config:",
+                "        "+TestEntity.CONF_MAP_THING.getName()+":",
+                "          mykey: myval");
+        
+        String yaml = Joiner.on("\n").join(
+                "services:",
+                "- type: entity-with-keys");
+        
+        Entity app = createStartWaitAndLogApplication(yaml);
+        TestEntity entity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
+
+        // Check config key is listed
+        assertKeyEquals(entity, TestEntity.CONF_MAP_THING.getName(), "myDescription", java.util.Map.class, null, ImmutableMap.of("mykey", "myval"));
+
+        // Rebind, and then check again that the config key is listed
+        Entity newApp = rebind();
+        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren());
+        if (assertReboundVal) {
+            assertKeyEquals(newEntity, TestEntity.CONF_MAP_THING.getName(), "myDescription", java.util.Map.class, null, ImmutableMap.of("mykey", "myval"));
+        } else {
+            // TODO delete duplication from `assertKeyEquals`, when the above works!
+            ConfigKey<?> key = newEntity.getEntityType().getConfigKey(TestEntity.CONF_MAP_THING.getName());
+            assertEquals(key.getDescription(), "myDescription");
+            assertEquals(key.getType(), java.util.Map.class);
+            assertEquals(key.getDefaultValue(), null);
+        }
+    }
+    
     @Test
     public void testConfigParametersListedInType() throws Exception {
         addCatalogItems(
@@ -441,9 +513,8 @@ public class ConfigParametersYamlTest extends AbstractYamlRebindTest {
         assertEquals(env.get("TEST"), "myDefaultParamVal", "env="+env);
     }
 
-    // TODO: fails; it presumably gets the config key defined in java, rather than the brooklyn.parameters key
     // See https://issues.apache.org/jira/browse/BROOKLYN-328
-    @Test(groups={"WIP", "Broken"})
+    @Test
     public void testConfigParameterOverridingJavaConfig() throws Exception {
         String confName = TestEntity.CONF_OBJECT.getName();
         addCatalogItems(


[05/13] brooklyn-server git commit: ServiceFailureDetector yaml tests, and fix

Posted by he...@apache.org.
ServiceFailureDetector yaml tests, and fix


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/c856cd15
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/c856cd15
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/c856cd15

Branch: refs/heads/master
Commit: c856cd15112c046ae5f0c8b578b84a213b51bcc0
Parents: bcb9689
Author: Aled Sage <al...@gmail.com>
Authored: Wed Nov 16 09:51:43 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 28 21:11:48 2016 +0000

----------------------------------------------------------------------
 .../ServiceFailureDetectorYamlTest.java         | 189 +++++++++++++++++++
 .../core/sensor/SensorEventPredicates.java      |  81 ++++++++
 .../entity/RecordingSensorEventListener.java    |  23 +++
 .../policy/ha/ServiceFailureDetector.java       |  63 ++++---
 4 files changed, 329 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c856cd15/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlTest.java
new file mode 100644
index 0000000..4374c2b
--- /dev/null
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlTest.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.camp.brooklyn;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
+import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
+import org.apache.brooklyn.core.sensor.SensorEventPredicates;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.policy.ha.HASensors;
+import org.apache.brooklyn.policy.ha.ServiceFailureDetector;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+@Test
+public class ServiceFailureDetectorYamlTest extends AbstractYamlTest {
+    
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(ServiceFailureDetectorYamlTest.class);
+    
+    static final String INDICATOR_KEY_1 = "test-indicator-1";
+
+    static final String appId = "my-app";
+    static final String appVersion = "1.2.3";
+    static final String appVersionedId = appId + ":" + appVersion;
+    
+    static final String catalogYamlSimple = Joiner.on("\n").join(
+            "brooklyn.catalog:",
+            "  id: " + appId,
+            "  version: " + appVersion,
+            "  itemType: entity",
+            "  item:",
+            "    type: " + TestEntity.class.getName(),
+            "    brooklyn.enrichers:",
+            "    - type: " + ServiceFailureDetector.class.getName());
+
+    static final String catalogYamlWithDsl = Joiner.on("\n").join(
+            "brooklyn.catalog:",
+            "  id: my-app",
+            "  version: 1.2.3",
+            "  itemType: entity",
+            "  item:",
+            "    services:",
+            "    - type: " + TestEntity.class.getName(),//FailingEntity.class.getName(),
+            "      brooklyn.parameters:",
+            "      - name: custom.stabilizationDelay",
+            "        type: " + Duration.class.getName(),
+            "        default: 1ms",
+            "      - name: custom.republishTime",
+            "        type: " + Duration.class.getName(),
+            "        default: 1m",
+            "      brooklyn.enrichers:",
+            "      - type: " + ServiceFailureDetector.class.getName(),
+            "        brooklyn.config:",
+            "          serviceOnFire.stabilizationDelay: $brooklyn:config(\"custom.stabilizationDelay\")",
+            "          entityFailed.stabilizationDelay: $brooklyn:config(\"custom.stabilizationDelay\")",
+            "          entityRecovered.stabilizationDelay: $brooklyn:config(\"custom.stabilizationDelay\")",
+            "          entityFailed.republishTime: $brooklyn:config(\"custom.republishTime\")");
+
+    static final String catalogYamlWithDslReferenceParentDefault = Joiner.on("\n").join(
+            "brooklyn.catalog:",
+            "  id: my-app",
+            "  version: 1.2.3",
+            "  itemType: entity",
+            "  item:",
+            "    brooklyn.parameters:",
+            "    - name: custom.stabilizationDelay",
+            "      type: " + Duration.class.getName(),
+            "      default: 1ms",
+            "    - name: custom.republishTime",
+            "      type: " + Duration.class.getName(),
+            "      default: 1m",
+            "    services:",
+            "    - type: " + TestEntity.class.getName(),//FailingEntity.class.getName(),
+            "      brooklyn.enrichers:",
+            "      - type: " + ServiceFailureDetector.class.getName(),
+            "        brooklyn.config:",
+            "          serviceOnFire.stabilizationDelay: $brooklyn:config(\"custom.stabilizationDelay\")",
+            "          entityFailed.stabilizationDelay: $brooklyn:config(\"custom.stabilizationDelay\")",
+            "          entityRecovered.stabilizationDelay: $brooklyn:config(\"custom.stabilizationDelay\")",
+            "          entityFailed.republishTime: $brooklyn:config(\"custom.republishTime\")");
+
+    @Test
+    public void testDefaults() throws Exception {
+        runTest(catalogYamlSimple, appVersionedId);
+    }
+    
+    @Test
+    public void testWithDslConfig() throws Exception {
+        Entity app = runTest(catalogYamlWithDsl, appVersionedId);
+        
+        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
+        ServiceFailureDetector newEnricher = assertHasEnricher(newEntity, ServiceFailureDetector.class);
+        assertEnricherConfigMatchesDsl(newEnricher);
+    }
+
+    @Test
+    public void testWithDslConfigReferenceParentDefault() throws Exception {
+        Entity app = runTest(catalogYamlWithDslReferenceParentDefault, appVersionedId);
+        
+        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
+        ServiceFailureDetector newEnricher = assertHasEnricher(newEntity, ServiceFailureDetector.class);
+        assertEnricherConfigMatchesDsl(newEnricher);
+    }
+    
+    protected Entity runTest(String catalogYaml, String appId) throws Exception {
+        addCatalogItems(catalogYaml);
+
+        String appYaml = Joiner.on("\n").join(
+                "services:",
+                "- type: " + appId);
+        Entity app = createStartWaitAndLogApplication(appYaml);
+        TestEntity entity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
+        assertHasEnricher(entity, ServiceFailureDetector.class);
+        
+        // Confirm ServiceFailureDetector triggers event
+        RecordingSensorEventListener<Object> listener = subscribeToHaSensors(entity);
+        
+        ServiceNotUpLogic.updateNotUpIndicator(entity, INDICATOR_KEY_1, "Simulate a problem");
+        listener.assertHasEventEventually(SensorEventPredicates.sensorEqualTo(HASensors.ENTITY_FAILED));
+        listener.assertEventCount(1);
+        listener.clearEvents();
+        
+        ServiceNotUpLogic.clearNotUpIndicator(entity, INDICATOR_KEY_1);
+        listener.assertHasEventEventually(SensorEventPredicates.sensorEqualTo(HASensors.ENTITY_RECOVERED));
+        listener.assertEventCount(1);
+        
+        return app;
+    }
+    
+    protected static <T extends Enricher> T assertHasEnricher(Entity entity, Class<T> enricherClazz) {
+        Enricher enricher = Iterables.find(entity.enrichers(), Predicates.instanceOf(enricherClazz));
+        assertNotNull(enricher);
+        return enricherClazz.cast(enricher);
+    }
+    
+    protected static void assertEnricherConfig(Enricher enricher, Map<? extends ConfigKey<?>, ?> expectedVals) {
+        for (Map.Entry<? extends ConfigKey<?>, ?> entry : expectedVals.entrySet()) {
+            ConfigKey<?> key = entry.getKey();
+            Object actual = enricher.config().get(key);
+            assertEquals(actual, entry.getValue(), "key="+key+"; expected="+entry.getValue()+"; actual="+actual);
+        }
+    }
+    
+    protected static void assertEnricherConfigMatchesDsl(Enricher enricher) {
+        assertEnricherConfig(enricher, ImmutableMap.<ConfigKey<?>, Object>of(
+                ServiceFailureDetector.ENTITY_FAILED_STABILIZATION_DELAY, Duration.ONE_MILLISECOND,
+                ServiceFailureDetector.SERVICE_ON_FIRE_STABILIZATION_DELAY, Duration.ONE_MILLISECOND,
+                ServiceFailureDetector.ENTITY_RECOVERED_STABILIZATION_DELAY, Duration.ONE_MILLISECOND,
+                ServiceFailureDetector.ENTITY_FAILED_REPUBLISH_TIME, Duration.ONE_MINUTE));
+    }
+
+    protected static RecordingSensorEventListener<Object> subscribeToHaSensors(Entity entity) {
+        RecordingSensorEventListener<Object> listener = new RecordingSensorEventListener<>();
+        entity.subscriptions().subscribe(entity, HASensors.ENTITY_RECOVERED, listener);
+        entity.subscriptions().subscribe(entity, HASensors.ENTITY_FAILED, listener);
+        return listener;
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c856cd15/core/src/main/java/org/apache/brooklyn/core/sensor/SensorEventPredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/SensorEventPredicates.java b/core/src/main/java/org/apache/brooklyn/core/sensor/SensorEventPredicates.java
new file mode 100644
index 0000000..00eb996
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/SensorEventPredicates.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.sensor;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.util.guava.SerializablePredicate;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+
+public class SensorEventPredicates {
+
+    public static Predicate<SensorEvent<?>> sensorEqualTo(final Sensor<?> val) {
+        return sensorSatisfies(Predicates.<Sensor<?>>equalTo(val));
+    }
+    
+    public static Predicate<SensorEvent<?>> sensorSatisfies(final Predicate<? super Sensor<?>> condition) {
+        return new SensorSatisfies(condition);
+    }
+    
+    protected static class SensorSatisfies implements SerializablePredicate<SensorEvent<?>> {
+        private static final long serialVersionUID = -3585200249520308941L;
+        
+        protected final Predicate<? super Sensor<?>> condition;
+        protected SensorSatisfies(Predicate<? super Sensor<?>> condition) {
+            this.condition = condition;
+        }
+        @Override
+        public boolean apply(@Nullable SensorEvent<?> input) {
+            return (input != null) && condition.apply(input.getSensor());
+        }
+        @Override
+        public String toString() {
+            return "sensorSatisfies("+condition+")";
+        }
+    }
+
+    public static <T> Predicate<SensorEvent<T>> valueEqualTo(final T val) {
+        return valueSatisfies(Predicates.equalTo(val));
+    }
+    
+    public static <T> Predicate<SensorEvent<T>> valueSatisfies(final Predicate<? super T> condition) {
+        return new ValueSatisfies<T>(condition);
+    }
+    
+    protected static class ValueSatisfies<T> implements SerializablePredicate<SensorEvent<T>> {
+        private static final long serialVersionUID = 2805443606039228221L;
+        
+        protected final Predicate<? super T> condition;
+        protected ValueSatisfies(Predicate<? super T> condition) {
+            this.condition = condition;
+        }
+        @Override
+        public boolean apply(@Nullable SensorEvent<T> input) {
+            return (input != null) && condition.apply(input.getValue());
+        }
+        @Override
+        public String toString() {
+            return "valueSatisfies("+condition+")";
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c856cd15/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java b/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java
index e0c4ed0..c54a0fb 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java
@@ -28,10 +28,13 @@ import java.util.Objects;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.core.task.Tasks;
+import org.testng.Assert;
 
 import com.google.common.base.Function;
+import com.google.common.base.Predicate;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -98,6 +101,26 @@ public class RecordingSensorEventListener<T> implements SensorEventListener<T>,
                 .transform(new GetValueFunction<T>());
     }
 
+    public void assertHasEvent(Predicate<? super SensorEvent<T>> filter) {
+        for (SensorEvent<T> event : events) {
+            if (filter.apply(event)) {
+                return;
+            }
+        }
+        Assert.fail("No event matching filter "+ filter);
+    }
+
+    public void assertHasEventEventually(final Predicate<? super SensorEvent<T>> filter) {
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                assertHasEvent(filter);
+            }});
+    }
+    
+    public void assertEventCount(int expected) {
+        Assert.assertEquals(events.size(), expected, "events="+events);
+    }
+
     /**
      * Clears all events recorded by the listener.
      */

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c856cd15/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
index d36f25a..5c5aaeb 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
@@ -301,37 +301,46 @@ public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceStat
         return description;
     }
     
-    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @SuppressWarnings({ "rawtypes" })
     protected void recomputeAfterDelay(long delay) {
-        if (isRunning() && executorQueued.compareAndSet(false, true)) {
-            long now = System.currentTimeMillis();
-            delay = Math.max(0, Math.max(delay, (executorTime + MIN_PERIOD_BETWEEN_EXECS_MILLIS) - now));
-            if (LOG.isTraceEnabled()) LOG.trace("{} scheduling publish in {}ms", this, delay);
-            
-            Runnable job = new Runnable() {
-                @Override public void run() {
-                    try {
-                        executorTime = System.currentTimeMillis();
-                        executorQueued.set(false);
+        // TODO Execute in same thread as other onEvent calls are done in (i.e. same conceptually 
+        // single-threaded executor as the subscription-manager will use).
+        //
+        // TODO Disabling the use of executorQueued check - it was causing assertions to fail that 
+        // we'd triggered the ENTITY_FAILED/ENTITY_RECOVERED. Previously used:
+        //    if (executorQueued.compareAndSet(false, true)) {
+        // My guess is that the next call to onEvent() didn't always call recomputeAfterDelay with
+        // the recalculated desired delay, as desired by the skipped call. But not sure why.
+        
+        if (!isRunning()) return;
+
+        long now = System.currentTimeMillis();
+        delay = Math.max(0, Math.max(delay, (executorTime + MIN_PERIOD_BETWEEN_EXECS_MILLIS) - now));
+        if (LOG.isTraceEnabled()) LOG.trace("{} scheduling publish in {}ms", this, delay);
+        
+        Runnable job = new Runnable() {
+            @Override public void run() {
+                try {
+                    executorTime = System.currentTimeMillis();
+                    executorQueued.set(false);
 
-                        onEvent(null);
-                        
-                    } catch (Exception e) {
-                        if (isRunning()) {
-                            LOG.error("Error in enricher "+this+": "+e, e);
-                        } else {
-                            if (LOG.isDebugEnabled()) LOG.debug("Error in enricher "+this+" (but no longer running): "+e, e);
-                        }
-                    } catch (Throwable t) {
-                        LOG.error("Error in enricher "+this+": "+t, t);
-                        throw Exceptions.propagate(t);
+                    onEvent(null);
+                    
+                } catch (Exception e) {
+                    if (isRunning()) {
+                        LOG.error("Error in enricher "+this+": "+e, e);
+                    } else {
+                        if (LOG.isDebugEnabled()) LOG.debug("Error in enricher "+this+" (but no longer running): "+e, e);
                     }
+                } catch (Throwable t) {
+                    LOG.error("Error in enricher "+this+": "+t, t);
+                    throw Exceptions.propagate(t);
                 }
-            };
-            
-            ScheduledTask task = new ScheduledTask(MutableMap.of("delay", Duration.of(delay, TimeUnit.MILLISECONDS)), new BasicTask(job));
-            ((EntityInternal)entity).getExecutionContext().submit(task);
-        }
+            }
+        };
+        
+        ScheduledTask task = new ScheduledTask(MutableMap.of("delay", Duration.of(delay, TimeUnit.MILLISECONDS)), new BasicTask(job));
+        ((EntityInternal)entity).getExecutionContext().submit(task);
     }
     
     private String getTimeStringSince(Long time) {


[12/13] brooklyn-server git commit: Add MapConfigKey.toString

Posted by he...@apache.org.
Add MapConfigKey.toString

Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/131d356c
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/131d356c
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/131d356c

Branch: refs/heads/master
Commit: 131d356c5e3e167aaabd48cffbf0e5a8370be88d
Parents: a9ec838
Author: Aled Sage <al...@gmail.com>
Authored: Thu Nov 17 14:48:41 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 28 21:11:48 2016 +0000

----------------------------------------------------------------------
 .../java/org/apache/brooklyn/core/config/ListConfigKey.java     | 5 +++++
 .../main/java/org/apache/brooklyn/core/config/MapConfigKey.java | 5 +++++
 .../main/java/org/apache/brooklyn/core/config/SetConfigKey.java | 5 +++++
 3 files changed, 15 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/131d356c/core/src/main/java/org/apache/brooklyn/core/config/ListConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/config/ListConfigKey.java b/core/src/main/java/org/apache/brooklyn/core/config/ListConfigKey.java
index 06a29bd..816af99 100644
--- a/core/src/main/java/org/apache/brooklyn/core/config/ListConfigKey.java
+++ b/core/src/main/java/org/apache/brooklyn/core/config/ListConfigKey.java
@@ -73,6 +73,11 @@ public class ListConfigKey<V> extends AbstractCollectionConfigKey<List<? extends
     }
 
     @Override
+    public String toString() {
+        return String.format("%s[ListConfigKey:%s]", name, getTypeName());
+    }
+
+    @Override
     protected List<Object> merge(boolean unmodifiable, Iterable<?>... sets) {
         MutableList<Object> result = MutableList.of();
         for (Iterable<?> set: sets) result.addAll(set);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/131d356c/core/src/main/java/org/apache/brooklyn/core/config/MapConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/config/MapConfigKey.java b/core/src/main/java/org/apache/brooklyn/core/config/MapConfigKey.java
index a0b9bd7..367259d 100644
--- a/core/src/main/java/org/apache/brooklyn/core/config/MapConfigKey.java
+++ b/core/src/main/java/org/apache/brooklyn/core/config/MapConfigKey.java
@@ -147,6 +147,11 @@ public class MapConfigKey<V> extends AbstractStructuredConfigKey<Map<String,V>,M
         super((Class)Map.class, subType, name, description, defaultValue);
     }
 
+    @Override
+    public String toString() {
+        return String.format("%s[MapConfigKey:%s]", name, getTypeName());
+    }
+
     public ConfigKey<V> subKey(String subName) {
         return super.subKey(subName);
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/131d356c/core/src/main/java/org/apache/brooklyn/core/config/SetConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/config/SetConfigKey.java b/core/src/main/java/org/apache/brooklyn/core/config/SetConfigKey.java
index f199c38..55c9a05 100644
--- a/core/src/main/java/org/apache/brooklyn/core/config/SetConfigKey.java
+++ b/core/src/main/java/org/apache/brooklyn/core/config/SetConfigKey.java
@@ -64,6 +64,11 @@ public class SetConfigKey<V> extends AbstractCollectionConfigKey<Set<? extends V
     }
 
     @Override
+    public String toString() {
+        return String.format("%s[SetConfigKey:%s]", name, getTypeName());
+    }
+
+    @Override
     protected Set<Object> merge(boolean unmodifiable, Iterable<?>... sets) {
         MutableSet<Object> result = MutableSet.of();
         for (Iterable<?> set: sets) result.addAll(set);


[10/13] brooklyn-server git commit: entity.setConfig(key, v): lookup ownKey

Posted by he...@apache.org.
entity.setConfig(key,v): lookup ownKey

Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/9d120a80
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/9d120a80
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/9d120a80

Branch: refs/heads/master
Commit: 9d120a8003bfb470acb38be7aad97bc53abeff70
Parents: 131d356
Author: Aled Sage <al...@gmail.com>
Authored: Thu Nov 17 14:48:15 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 28 21:11:48 2016 +0000

----------------------------------------------------------------------
 .../core/config/internal/AbstractConfigMapImpl.java  | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d120a80/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java b/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java
index 98d20ad..b81d836 100644
--- a/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java
@@ -163,13 +163,18 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i
         return putAllOwnConfigIntoSafely(ConfigBag.newInstance()).seal();
     }
 
-    public Object setConfig(ConfigKey<?> key, Object v) {
-        Object val = coerceConfigVal(key, v);
+    public Object setConfig(final ConfigKey<?> key, Object v) {
+        // Use our own key for writing, (e.g. in-case it should (or should not) be a structured key like MapConfigKey).
+        // This is same logic as for getConfig, except we only have to look at our own container.
+        ConfigKey<?> ownKey = getKeyAtContainer(getContainer(), key);
+        if (ownKey==null) ownKey = key;
+
+        Object val = coerceConfigVal(ownKey, v);
         Object oldVal;
-        if (key instanceof StructuredConfigKey) {
-            oldVal = ((StructuredConfigKey)key).applyValueToMap(val, ownConfig);
+        if (ownKey instanceof StructuredConfigKey) {
+            oldVal = ((StructuredConfigKey)ownKey).applyValueToMap(val, ownConfig);
         } else {
-            oldVal = ownConfig.put(key, val);
+            oldVal = ownConfig.put(ownKey, val);
         }
         postSetConfig();
         return oldVal;


[04/13] brooklyn-server git commit: Time.makeTimeString: avoid NPE if arg is null

Posted by he...@apache.org.
Time.makeTimeString: avoid NPE if arg is null


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/bcb96892
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/bcb96892
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/bcb96892

Branch: refs/heads/master
Commit: bcb96892991b72f7170e11b26140eff1fba8525d
Parents: aa14b84
Author: Aled Sage <al...@gmail.com>
Authored: Wed Nov 16 09:47:27 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 28 21:11:48 2016 +0000

----------------------------------------------------------------------
 .../org/apache/brooklyn/util/time/Duration.java |  6 +-
 .../org/apache/brooklyn/util/time/Time.java     | 74 +++++++++++++-------
 .../org/apache/brooklyn/util/time/TimeTest.java | 31 +++++++-
 3 files changed, 83 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/bcb96892/utils/common/src/main/java/org/apache/brooklyn/util/time/Duration.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/time/Duration.java b/utils/common/src/main/java/org/apache/brooklyn/util/time/Duration.java
index 76217a0..473aef3 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/time/Duration.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/time/Duration.java
@@ -137,8 +137,10 @@ public class Duration implements Comparable<Duration>, Serializable {
 
     /** 
      * See {@link Time#parseElapsedTime(String)}; 
-     * also accepts "forever" (and for those who prefer things exceedingly accurate, "practically_forever"). 
-     * Also see {@link #of(Object)}. */
+     * also accepts "forever" (and for those who prefer things exceedingly accurate, "practically_forever").
+     * If null or blank or 'null' is passed in, then null will be returned. 
+     * Also see {@link #of(Object)}.
+     */
     public static Duration parse(String textualDescription) {
         if (Strings.isBlank(textualDescription)) return null;
         if ("null".equalsIgnoreCase(textualDescription)) return null;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/bcb96892/utils/common/src/main/java/org/apache/brooklyn/util/time/Time.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/time/Time.java b/utils/common/src/main/java/org/apache/brooklyn/util/time/Time.java
index 89c62ad..ef445d5 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/time/Time.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/time/Time.java
@@ -87,7 +87,7 @@ public class Time {
         return makeDateString(date, format, null);
     }
     /** as {@link #makeDateString(Date, String, TimeZone)} for the given time zone; consider {@link TimeZone#GMT} */
-    public static String makeDateString(Date date, String format, TimeZone tz) {
+    public static String makeDateString(Date date, String format, @Nullable TimeZone tz) {
         SimpleDateFormat fmt = new SimpleDateFormat(format);
         if (tz!=null) fmt.setTimeZone(tz);
         return fmt.format(date);
@@ -101,7 +101,9 @@ public class Time {
         return makeDateString(date.getTime(), format, date.getTimeZone());
     }
 
-    public static Function<Long, String> toDateString() { return dateString; }
+    public static Function<Long, String> toDateString() {
+        return dateString;
+    }
     private static Function<Long, String> dateString = new Function<Long, String>() {
             @Override
             @Nullable
@@ -136,7 +138,9 @@ public class Time {
         return new SimpleDateFormat(DATE_FORMAT_SIMPLE_STAMP).format(new Date(date));
     }
 
-    public static Function<Long, String> toDateStampString() { return dateStampString; }
+    public static Function<Long, String> toDateStampString() {
+        return dateStampString;
+    }
     private static Function<Long, String> dateStampString = new Function<Long, String>() {
             @Override
             @Nullable
@@ -156,8 +160,11 @@ public class Time {
         long nanos = unit.toNanos(t);
         return makeTimeStringNanoRounded(nanos);
     }
-    public static String makeTimeStringRounded(Stopwatch timer) {
-        return makeTimeStringRounded(timer.elapsed(TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS);
+    /**
+     * A nice string representation of the stopwatch's elapsed time; or null if null is passed in.
+     */
+    public static String makeTimeStringRounded(@Nullable Stopwatch timer) {
+        return (timer == null) ? null : makeTimeStringRounded(timer.elapsed(TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS);
     }
     /** @see #makeTimeString(long, boolean) */
     public static String makeTimeStringExact(long t) {
@@ -171,13 +178,19 @@ public class Time {
     public static String makeTimeStringRoundedSince(long utc) {
         return makeTimeString(System.currentTimeMillis() - utc, true);
     }
-    /** @see #makeTimeString(long, boolean) */
-    public static String makeTimeStringExact(Duration d) {
-        return makeTimeStringNanoExact(d.toNanoseconds());
+    /**
+     * A nice string representation of the duration; or null if null is passed in.
+     * @see #makeTimeString(long, boolean)
+     */
+    public static String makeTimeStringExact(@Nullable Duration d) {
+        return (d == null) ? null : makeTimeStringNanoExact(d.toNanoseconds());
     }
-    /** @see #makeTimeString(long, boolean) */
-    public static String makeTimeStringRounded(Duration d) {
-        return makeTimeStringNanoRounded(d.toNanoseconds());
+    /**
+     * A nice string representation of the duration; or null if null is passed in.
+     * @see #makeTimeString(long, boolean)
+     */
+    public static String makeTimeStringRounded(@Nullable Duration d) {
+        return (d == null) ? null : makeTimeStringNanoRounded(d.toNanoseconds());
     }
     /** given an elapsed time, makes it readable, eg 44d 6h, or 8s 923ms, optionally rounding */
     public static String makeTimeString(long t, boolean round) {
@@ -282,7 +295,9 @@ public class Time {
         return Strings.removeAllFromEnd(result, " ");
     }
 
-    public static Function<Long, String> fromLongToTimeStringExact() { return LONG_TO_TIME_STRING_EXACT; }
+    public static Function<Long, String> fromLongToTimeStringExact() {
+        return LONG_TO_TIME_STRING_EXACT;
+    }
     private static final Function<Long, String> LONG_TO_TIME_STRING_EXACT = new FunctionLongToTimeStringExact();
     private static final class FunctionLongToTimeStringExact implements Function<Long, String> {
         @Override @Nullable
@@ -292,8 +307,11 @@ public class Time {
         }
     }
 
-    /** @deprecated since 0.7.0 use {@link #fromLongToTimeStringExact()} */ @Deprecated
-    public static Function<Long, String> toTimeString() { return timeString; }
+    /** @deprecated since 0.7.0 use {@link #fromLongToTimeStringExact()} */
+    @Deprecated
+    public static Function<Long, String> toTimeString() {
+        return timeString;
+    }
     @Deprecated
     private static Function<Long, String> timeString = new Function<Long, String>() {
             @Override
@@ -304,7 +322,9 @@ public class Time {
             }
         };
         
-    public static Function<Long, String> fromLongToTimeStringRounded() { return LONG_TO_TIME_STRING_ROUNDED; }
+    public static Function<Long, String> fromLongToTimeStringRounded() {
+        return LONG_TO_TIME_STRING_ROUNDED;
+    }
     private static final Function<Long, String> LONG_TO_TIME_STRING_ROUNDED = new FunctionLongToTimeStringRounded();
     private static final class FunctionLongToTimeStringRounded implements Function<Long, String> {
         @Override @Nullable
@@ -314,8 +334,11 @@ public class Time {
         }
     }
 
-    /** @deprecated since 0.7.0 use {@link #fromLongToTimeStringRounded()} */ @Deprecated
-    public static Function<Long, String> toTimeStringRounded() { return timeStringRounded; }
+    /** @deprecated since 0.7.0 use {@link #fromLongToTimeStringRounded()} */
+    @Deprecated
+    public static Function<Long, String> toTimeStringRounded() {
+        return timeStringRounded;
+    }
     @Deprecated
     private static Function<Long, String> timeStringRounded = new Function<Long, String>() {
         @Override
@@ -326,7 +349,9 @@ public class Time {
         }
     };
 
-    public static Function<Duration, String> fromDurationToTimeStringRounded() { return DURATION_TO_TIME_STRING_ROUNDED; }
+    public static Function<Duration, String> fromDurationToTimeStringRounded() {
+        return DURATION_TO_TIME_STRING_ROUNDED;
+    }
     private static final Function<Duration, String> DURATION_TO_TIME_STRING_ROUNDED = new FunctionDurationToTimeStringRounded();
     private static final class FunctionDurationToTimeStringRounded implements Function<Duration, String> {
         @Override @Nullable
@@ -412,7 +437,7 @@ public class Time {
     }
     
     /** Convenience for {@link Duration#parse(String)}. */
-    public static Duration parseDuration(String timeString) {
+    public static Duration parseDuration(@Nullable String timeString) {
         return Duration.parse(timeString);
     }
     
@@ -438,12 +463,13 @@ public class Time {
      * -1 on blank or never or off or false.
      * Assumes unit is millisections if no unit is specified.
      * 
-     * @throws NumberFormatException if cannot be parsed (or if null)
+     * @throws NullPointerException if arg is null
+     * @throws NumberFormatException if cannot be parsed
      */
     public static double parseElapsedTimeAsDouble(final String timeStringOrig) {
         String timeString = timeStringOrig;
         if (timeString==null)
-            throw new NumberFormatException("GeneralHelper.parseTimeString cannot parse a null string");
+            throw new NullPointerException("GeneralHelper.parseTimeString cannot parse a null string");
         try {
             double d = Double.parseDouble(timeString);
             return d;
@@ -522,7 +548,7 @@ public class Time {
     
     /** As {@link #parseCalendar(String)} but returning a {@link Date},
      * (i.e. a record where the time zone has been applied and forgotten). */
-    public static Date parseDate(String input) {
+    public static Date parseDate(@Nullable String input) {
         if (input==null) return null;
         return parseCalendarMaybe(input).get().getTime();
     }
@@ -536,13 +562,13 @@ public class Time {
      * <p>
      * Other formats including locale-specific variants, e.g. recognising month names,
      * are supported but this may vary from platform to platform and may change between versions. */
-    public static Calendar parseCalendar(String input) {
+    public static Calendar parseCalendar(@Nullable String input) {
         if (input==null) return null;
         return parseCalendarMaybe(input).get();
     }
     
     /** as {@link #parseCalendar(String)} but returning a {@link Maybe} rather than throwing or returning null */
-    public static Maybe<Calendar> parseCalendarMaybe(String input) {
+    public static Maybe<Calendar> parseCalendarMaybe(@Nullable String input) {
         if (input==null) return Maybe.absent("value is null");
         input = input.trim();
         Maybe<Calendar> result;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/bcb96892/utils/common/src/test/java/org/apache/brooklyn/util/time/TimeTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/time/TimeTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/time/TimeTest.java
index 60945cf..e3c8167 100644
--- a/utils/common/src/test/java/org/apache/brooklyn/util/time/TimeTest.java
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/time/TimeTest.java
@@ -20,12 +20,15 @@ package org.apache.brooklyn.util.time;
 
 import java.util.Date;
 import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
 
-import org.apache.brooklyn.util.time.Duration;
-import org.apache.brooklyn.util.time.Time;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.google.common.base.Stopwatch;
+import com.google.common.base.Ticker;
+
 @Test
 public class TimeTest {
 
@@ -141,6 +144,30 @@ public class TimeTest {
     public void testMakeStringRoundedNegative() { checkR(-1, "-1ms"); }
 
     @Test
+    public void testMakeTimeStringFromDuration() {
+        Assert.assertNull(Time.makeTimeStringExact((Duration)null));
+        Assert.assertEquals(Time.makeTimeStringExact(Duration.millis(1100)), "1s 100ms");
+        
+        Assert.assertNull(Time.makeTimeStringRounded((Duration)null));
+        Assert.assertEquals(Time.makeTimeStringRounded(Duration.millis(1100)), "1.10s");
+    }
+
+    @Test
+    public void testMakeTimeStringFromStopwatch() {
+        final AtomicLong time = new AtomicLong();
+        Ticker ticker = new Ticker() {
+            @Override public long read() {
+                return time.get();
+            }
+        };
+        Assert.assertNull(Time.makeTimeStringRounded((Stopwatch)null));
+        
+        Stopwatch stopwatch = Stopwatch.createStarted(ticker);
+        time.set(TimeUnit.MILLISECONDS.toNanos(1100));
+        Assert.assertEquals(Time.makeTimeStringRounded(stopwatch), "1.10s");
+    }
+
+    @Test
     public void testElapsedSince() {
         long aFewSecondsAgo = System.currentTimeMillis() - 7*1000;
         


[03/13] brooklyn-server git commit: Test+fix yaml config param overriding java configKey

Posted by he...@apache.org.
Test+fix yaml config param overriding java configKey

Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/dba74943
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/dba74943
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/dba74943

Branch: refs/heads/master
Commit: dba74943bae5b86c6fe6e7d145e2c20dce58dd9b
Parents: 5d2d9b3
Author: Aled Sage <al...@gmail.com>
Authored: Wed Nov 16 21:36:16 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 28 21:11:48 2016 +0000

----------------------------------------------------------------------
 .../camp/brooklyn/ConfigParametersYamlTest.java | 25 ++++++++++++++++++++
 .../brooklyn/core/objs/BasicSpecParameter.java  |  2 +-
 2 files changed, 26 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dba74943/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
index 2f655c6..79ab2a4 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
@@ -109,7 +109,32 @@ public class ConfigParametersYamlTest extends AbstractYamlRebindTest {
         assertKeyEquals(newEntity, "testConfigParametersListedInType.mykey", "myDescription", String.class, "myDefaultVal", "myOverridingVal");
     }
     
+    @Test
+    public void testConfigParameterOverridingJavaListedInType() throws Exception {
+        addCatalogItems(
+                "brooklyn.catalog:",
+                "  itemType: entity",
+                "  items:",
+                "  - id: entity-with-keys",
+                "    item:",
+                "      type: "+TestEntity.class.getName(),
+                "      brooklyn.parameters:",
+                "      - name: " + TestEntity.CONF_NAME.getName(),
+                "        description: myDescription",
+                "        type: String",
+                "        default: myDefaultYamlVal");
+        
+        String yaml = Joiner.on("\n").join(
+                "services:",
+                "- type: entity-with-keys");
+        
+        Entity app = createStartWaitAndLogApplication(yaml);
+        TestEntity entity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
 
+        // Check config key is listed
+        assertKeyEquals(entity, TestEntity.CONF_NAME.getName(), "myDescription", String.class, "myDefaultYamlVal", "myDefaultYamlVal");
+    }
+    
     @Test
     public void testConfigParametersListedInType() throws Exception {
         addCatalogItems(

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dba74943/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java b/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java
index 82b29fb..cc9d66a 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java
@@ -118,7 +118,7 @@ public class BasicSpecParameter<T> implements SpecParameter<T>{
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(label, pinned, configKey);
+        return Objects.hashCode(configKey);
     }
 
     @Override


[08/13] brooklyn-server git commit: BROOKLYN-345: Persist entity’s dynamic config keys

Posted by he...@apache.org.
BROOKLYN-345: Persist entity\u2019s dynamic config keys

Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/28146711
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/28146711
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/28146711

Branch: refs/heads/master
Commit: 28146711f7204dcbcbdfdf5d347e966463062562
Parents: 3a7b972
Author: Aled Sage <al...@gmail.com>
Authored: Wed Nov 16 12:34:07 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 28 21:11:48 2016 +0000

----------------------------------------------------------------------
 .../api/mgmt/rebind/mementos/EntityMemento.java |  3 +++
 .../mgmt/rebind/BasicEntityRebindSupport.java   | 20 ++++++++-------
 .../mgmt/rebind/dto/BasicEntityMemento.java     | 27 +++++++++++++++++---
 .../mgmt/rebind/dto/MementosGenerators.java     |  2 ++
 4 files changed, 39 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28146711/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/EntityMemento.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/EntityMemento.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/EntityMemento.java
index 4c74695..d073836 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/EntityMemento.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/EntityMemento.java
@@ -39,6 +39,9 @@ public interface EntityMemento extends Memento, TreeNode {
     /** all dynamic effectors (ie differences between those registered on the entity type */ 
     public List<Effector<?>> getEffectors();
 
+    /** all dynamic config keys (i.e. differences between those registered on the entity type) */
+    public List<ConfigKey<?>> getDynamicConfigKeys();
+
     public Map<ConfigKey<?>, Object> getConfig();
 
     /** true if the entity is top-level (parentless) and an application

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28146711/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java
index 4165191..a206997 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java
@@ -24,7 +24,6 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.mgmt.rebind.RebindContext;
@@ -58,7 +57,7 @@ public class BasicEntityRebindSupport extends AbstractBrooklynObjectRebindSuppor
 
     private static final Logger LOG = LoggerFactory.getLogger(BasicEntityRebindSupport.class);
     
-    private final EntityLocal entity;
+    private final EntityInternal entity;
     
     public BasicEntityRebindSupport(AbstractEntity entity) {
         super(entity);
@@ -84,8 +83,11 @@ public class BasicEntityRebindSupport extends AbstractBrooklynObjectRebindSuppor
     @Override
     @SuppressWarnings("unchecked")
     protected void addCustoms(RebindContext rebindContext, EntityMemento memento) {
-        for (Effector<?> eff: memento.getEffectors()) {
-            ((EntityInternal)entity).getMutableEntityType().addEffector(eff);
+        for (ConfigKey<?> key : memento.getDynamicConfigKeys()) {
+            entity.getMutableEntityType().addConfigKey(key);
+        }
+        for (Effector<?> eff : memento.getEffectors()) {
+            entity.getMutableEntityType().addEffector(eff);
         }
     
         for (Map.Entry<AttributeSensor<?>, Object> entry : memento.getAttributes().entrySet()) {
@@ -94,7 +96,7 @@ public class BasicEntityRebindSupport extends AbstractBrooklynObjectRebindSuppor
                 Object value = entry.getValue();
                 @SuppressWarnings("unused") // just to ensure we can load the declared type? or maybe not needed
                 Class<?> type = (key.getType() != null) ? key.getType() : rebindContext.loadClass(key.getTypeName());
-                ((EntityInternal)entity).sensors().setWithoutPublishing((AttributeSensor<Object>)key, value);
+                entity.sensors().setWithoutPublishing((AttributeSensor<Object>)key, value);
             } catch (Exception e) {
                 LOG.warn("Error adding custom sensor "+entry+" when rebinding "+entity+" (rethrowing): "+e);
                 throw Exceptions.propagate(e);
@@ -124,8 +126,8 @@ public class BasicEntityRebindSupport extends AbstractBrooklynObjectRebindSuppor
             }
         }
         
-        ((EntityInternal)entity).config().putAll(memento.getConfigUnmatched());
-        ((EntityInternal)entity).config().refreshInheritedConfig();
+        entity.config().putAll(memento.getConfigUnmatched());
+        entity.config().refreshInheritedConfig();
     }
     
     @Override
@@ -169,7 +171,7 @@ public class BasicEntityRebindSupport extends AbstractBrooklynObjectRebindSuppor
             AbstractFeed feed = (AbstractFeed) rebindContext.lookup().lookupFeed(feedId);
             if (feed != null) {
                 try {
-                    ((EntityInternal)entity).feeds().addFeed(feed);
+                    entity.feeds().add(feed);
                 } catch (Exception e) {
                     rebindContext.getExceptionHandler().onAddFeedFailed(entity, feed, e);
                 }
@@ -236,7 +238,7 @@ public class BasicEntityRebindSupport extends AbstractBrooklynObjectRebindSuppor
         for (String id : memento.getLocations()) {
             Location loc = rebindContext.lookup().lookupLocation(id);
             if (loc != null) {
-                ((EntityInternal)entity).addLocationsWithoutPublishing(ImmutableList.of(loc));
+                entity.addLocationsWithoutPublishing(ImmutableList.of(loc));
             } else {
                 LOG.warn("Location not found; discarding location {} of entity {}({})",
                         new Object[] {id, memento.getType(), memento.getId()});

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28146711/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
index f06ff36..a150fd5 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
@@ -30,17 +30,18 @@ import org.apache.brooklyn.api.mgmt.rebind.mementos.EntityMemento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.TreeNode;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.Sanitizer;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.objs.BrooklynTypes;
 import org.apache.brooklyn.core.sensor.Sensors;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect;
 import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
@@ -66,6 +67,7 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
 
     public static class Builder extends AbstractTreeNodeMemento.Builder<Builder> {
         protected Boolean isTopLevelApp;
+        protected List<ConfigKey<?>> configKeys = Lists.newArrayList();
         protected Map<ConfigKey<?>, Object> config = Maps.newLinkedHashMap();
         protected Map<String, Object> configUnmatched = Maps.newLinkedHashMap();
         protected Map<AttributeSensor<?>, Object> attributes = Maps.newLinkedHashMap();
@@ -117,6 +119,7 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
     private transient Map<String, Sensor<?>> staticSensorKeys;
     private List<Effector<?>> effectors;
     
+    private transient List<ConfigKey<?>> allConfigKeys;
     private transient Map<ConfigKey<?>, Object> configByKey;
     private transient Map<String, Object> configUnmatched;
     private transient Map<AttributeSensor<?>, Object> attributesByKey;
@@ -139,17 +142,28 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
         
         effectors = toPersistedList(builder.effectors);
         
+        allConfigKeys = builder.configKeys;
         configByKey = builder.config;
         configUnmatched = builder.configUnmatched;
         attributesByKey = builder.attributes;
         
+        staticConfigKeys = getStaticConfigKeys();
+        staticSensorKeys = getStaticSensorKeys();
+        
         if (configByKey!=null) {
             configKeys = Maps.newLinkedHashMap();
             config = Maps.newLinkedHashMap();
+            
+            for (ConfigKey<?> key : allConfigKeys) {
+                if (!key.equals(staticConfigKeys.get(key.getName()))) {
+                    configKeys.put(key.getName(), key);
+                }
+            }
             for (Map.Entry<ConfigKey<?>, Object> entry : configByKey.entrySet()) {
                 ConfigKey<?> key = entry.getKey();
-                if (!key.equals(getStaticConfigKeys().get(key.getName())))
+                if (!configKeys.containsKey(key) && !key.equals(staticConfigKeys.get(key.getName()))) {
                     configKeys.put(key.getName(), key);
+                }
                 config.put(key.getName(), entry.getValue());
             }
             configKeys = toPersistedMap(configKeys);
@@ -165,7 +179,7 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
             attributes = Maps.newLinkedHashMap();
             for (Map.Entry<AttributeSensor<?>, Object> entry : attributesByKey.entrySet()) {
                 AttributeSensor<?> key = entry.getKey();
-                if (!key.equals(getStaticSensorKeys().get(key.getName())))
+                if (!key.equals(staticSensorKeys.get(key.getName())))
                     attributeKeys.put(key.getName(), key);
                 attributes.put(key.getName(), entry.getValue());
             }
@@ -262,6 +276,11 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
     }
     
     @Override
+    public List<ConfigKey<?>> getDynamicConfigKeys() {
+        return (configKeys == null) ? ImmutableList.<ConfigKey<?>>of() : ImmutableList.copyOf(configKeys.values());
+    }
+    
+    @Override
     public Map<ConfigKey<?>, Object> getConfig() {
         if (configByKey == null) postDeserialize();
         return Collections.unmodifiableMap(configByKey);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28146711/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
index 33d38a1..6f62b49 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
@@ -178,6 +178,8 @@ public class MementosGenerators {
         
         builder.isTopLevelApp = (entity instanceof Application && entity.getParent() == null);
 
+        builder.configKeys.addAll(entity.getEntityType().getConfigKeys());
+        
         Map<ConfigKey<?>, ?> localConfig = entity.config().getAllLocalRaw();
         for (Map.Entry<ConfigKey<?>, ?> entry : localConfig.entrySet()) {
             ConfigKey<?> key = checkNotNull(entry.getKey(), localConfig);


[13/13] brooklyn-server git commit: This closes #440

Posted by he...@apache.org.
This closes #440


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/56496fa5
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/56496fa5
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/56496fa5

Branch: refs/heads/master
Commit: 56496fa54c90d7f5de45514d06356c5be152ad99
Parents: 721ced7 e28c4b3
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Nov 29 13:40:02 2016 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Nov 29 13:40:02 2016 +0000

----------------------------------------------------------------------
 .../api/mgmt/rebind/mementos/EntityMemento.java |   3 +
 .../BrooklynComponentTemplateResolver.java      |  36 +++-
 .../camp/brooklyn/AbstractYamlRebindTest.java   |   1 +
 .../camp/brooklyn/ConfigNestedYamlTest.java     |   2 +-
 .../camp/brooklyn/ConfigParametersYamlTest.java | 192 +++++++++++++++---
 .../camp/brooklyn/DslAndRebindYamlTest.java     |  18 ++
 .../ServiceFailureDetectorYamlRebindTest.java   | 148 ++++++++++++++
 .../ServiceFailureDetectorYamlTest.java         | 200 +++++++++++++++++++
 .../catalog/SpecParameterUnwrappingTest.java    |   9 +-
 .../brooklyn/core/config/ListConfigKey.java     |   5 +
 .../brooklyn/core/config/MapConfigKey.java      |   5 +
 .../brooklyn/core/config/SetConfigKey.java      |   5 +
 .../config/internal/AbstractConfigMapImpl.java  |  15 +-
 .../mgmt/rebind/BasicEntityRebindSupport.java   |  20 +-
 .../mgmt/rebind/dto/BasicEntityMemento.java     |  49 +++--
 .../mgmt/rebind/dto/MementosGenerators.java     |   2 +
 .../brooklyn/core/objs/BasicSpecParameter.java  |   2 +-
 .../core/sensor/SensorEventPredicates.java      |  81 ++++++++
 .../entity/RecordingSensorEventListener.java    |  23 +++
 .../rebind/RecordingRebindExceptionHandler.java |  33 ++-
 .../core/sensor/SensorEventPredicatesTest.java  |  65 ++++++
 .../policy/ha/ServiceFailureDetector.java       |  97 +++++----
 .../org/apache/brooklyn/util/time/Duration.java |   6 +-
 .../org/apache/brooklyn/util/time/Time.java     |  74 ++++---
 .../org/apache/brooklyn/util/time/TimeTest.java |  31 ++-
 25 files changed, 994 insertions(+), 128 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/56496fa5/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------


[11/13] brooklyn-server git commit: Adds SensorEventPredicatesTest

Posted by he...@apache.org.
Adds SensorEventPredicatesTest


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/5d2d9b36
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/5d2d9b36
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/5d2d9b36

Branch: refs/heads/master
Commit: 5d2d9b36434c6ca5e9085ef7099cb7cd1f1f15d7
Parents: 2814671
Author: Aled Sage <al...@gmail.com>
Authored: Wed Nov 16 21:00:16 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 28 21:11:48 2016 +0000

----------------------------------------------------------------------
 .../core/sensor/SensorEventPredicatesTest.java  | 65 ++++++++++++++++++++
 1 file changed, 65 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5d2d9b36/core/src/test/java/org/apache/brooklyn/core/sensor/SensorEventPredicatesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/sensor/SensorEventPredicatesTest.java b/core/src/test/java/org/apache/brooklyn/core/sensor/SensorEventPredicatesTest.java
new file mode 100644
index 0000000..2011f1d
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/sensor/SensorEventPredicatesTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.sensor;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.util.core.sensor.SensorPredicates;
+import org.apache.brooklyn.util.text.StringPredicates;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+
+public class SensorEventPredicatesTest extends BrooklynAppUnitTestSupport {
+
+    private AttributeSensor<String> sensor1 = Sensors.newStringSensor("sensor1");
+    private AttributeSensor<String> sensor2 = Sensors.newStringSensor("sensor2");
+
+    @Test
+    public void testSensorEqualTo() throws Exception {
+        Predicate<SensorEvent<?>> predicate = SensorEventPredicates.sensorEqualTo(sensor1);
+        assertTrue(predicate.apply(new BasicSensorEvent<String>(sensor1, app, "myval")));
+        assertFalse(predicate.apply(new BasicSensorEvent<String>(sensor2, app, "myval")));
+    }
+    
+    @Test
+    public void testSensorSatisfies() throws Exception {
+        Predicate<SensorEvent<?>> predicate = SensorEventPredicates.sensorSatisfies(SensorPredicates.nameEqualTo("sensor1"));
+        assertTrue(predicate.apply(new BasicSensorEvent<String>(sensor1, app, "myval")));
+        assertFalse(predicate.apply(new BasicSensorEvent<String>(sensor2, app, "myval")));
+    }
+    
+    @Test
+    public void testValueEqualTo() throws Exception {
+        Predicate<SensorEvent<String>> predicate = SensorEventPredicates.valueEqualTo("myval");
+        assertTrue(predicate.apply(new BasicSensorEvent<String>(sensor1, app, "myval")));
+        assertFalse(predicate.apply(new BasicSensorEvent<String>(sensor1, app, "wrongVal")));
+    }
+    
+    @Test
+    public void testValueSatisfies() throws Exception {
+        Predicate<SensorEvent<String>> predicate = SensorEventPredicates.valueSatisfies(StringPredicates.containsLiteral("my"));
+        assertTrue(predicate.apply(new BasicSensorEvent<String>(sensor1, app, "myval")));
+        assertFalse(predicate.apply(new BasicSensorEvent<String>(sensor1, app, "wrongVal")));
+    }
+}


[07/13] brooklyn-server git commit: ServiceFailureDetector: persist lastPublished

Posted by he...@apache.org.
ServiceFailureDetector: persist lastPublished

Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/3a7b972b
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/3a7b972b
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/3a7b972b

Branch: refs/heads/master
Commit: 3a7b972b1876b1096c8a9a4b8d1879833681de84
Parents: b97cd17
Author: Aled Sage <al...@gmail.com>
Authored: Wed Nov 16 09:59:46 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 28 21:11:48 2016 +0000

----------------------------------------------------------------------
 .../brooklyn/policy/ha/ServiceFailureDetector.java     | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3a7b972b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
index 5c5aaeb..cba2abd 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
@@ -108,6 +108,15 @@ public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceStat
             .description("Publish failed state periodically at the specified intervals, null to disable.")
             .build();
 
+    /**
+     * Indicates the last event that was published (so we don't accidentally publish repeated
+     * ENTITY_FAILED, etc). Needs to be persisted so that on rebind we don't publish a duplicate
+     * (we'll only publish again if we are in a different state from before Brooklyn was last
+     * shutdown).
+     */
+    @SetFromFlag
+    protected LastPublished lastPublished = LastPublished.NONE;
+
     protected Long firstUpTime;
     
     protected Long currentFailureStartTime = null;
@@ -117,8 +126,6 @@ public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceStat
     protected Long publishEntityRecoveredTime = null;
     protected Long setEntityOnFireTime = null;
     
-    protected LastPublished lastPublished = LastPublished.NONE;
-
     private final AtomicBoolean executorQueued = new AtomicBoolean(false);
     private volatile long executorTime = 0;
 
@@ -230,6 +237,7 @@ public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceStat
                     }
                     lastPublished = LastPublished.FAILED;
                     entity.sensors().emit(HASensors.ENTITY_FAILED, new HASensors.FailureDescriptor(entity, getFailureDescription(now)));
+                    requestPersist();
                 } else {
                     recomputeIn = Math.min(recomputeIn, delayBeforeCheck);
                 }
@@ -241,6 +249,7 @@ public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceStat
                     publishEntityRecoveredTime = null;
                     lastPublished = LastPublished.RECOVERED;
                     entity.sensors().emit(HASensors.ENTITY_RECOVERED, new HASensors.FailureDescriptor(entity, null));
+                    requestPersist();
                 } else {
                     recomputeIn = Math.min(recomputeIn, delayBeforeCheck);
                 }


[02/13] brooklyn-server git commit: YAML config parsing: prefer brooklyn.parameters keys

Posted by he...@apache.org.
YAML config parsing: prefer brooklyn.parameters keys


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/92ff8201
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/92ff8201
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/92ff8201

Branch: refs/heads/master
Commit: 92ff8201714f4791137c63b836b128e734d82885
Parents: 9d120a8
Author: Aled Sage <al...@gmail.com>
Authored: Fri Nov 18 21:37:32 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 28 21:11:48 2016 +0000

----------------------------------------------------------------------
 .../BrooklynComponentTemplateResolver.java      | 36 ++++++++++++++++++--
 .../catalog/SpecParameterUnwrappingTest.java    |  9 +++--
 2 files changed, 39 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/92ff8201/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index ccf18c0..e968792 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -269,7 +269,7 @@ public class BrooklynComponentTemplateResolver {
         // For config values inherited from the super-type (be that the Java type or another catalog item
         // being extended), we lookup the config key to find out if the values should be merged, overridden or 
         // cleared.
-        
+
         ConfigBag bag = ConfigBag.newInstance((Map<Object, Object>) attrs.getStringKey(BrooklynCampReservedKeys.BROOKLYN_CONFIG));
         ConfigBag bagFlags = ConfigBag.newInstanceCopying(attrs);
         if (attrs.containsKey(BrooklynCampReservedKeys.BROOKLYN_FLAGS)) {
@@ -374,15 +374,45 @@ public class BrooklynComponentTemplateResolver {
      * Searches for config keys in the type, additional interfaces and the implementation (if specified)
      */
     private Collection<FlagConfigKeyAndValueRecord> findAllFlagsAndConfigKeyValues(EntitySpec<?> spec, ConfigBag bagFlags) {
+        // Matches the bagFlags against the names used in brooklyn.parameters, entity configKeys  
+        // and entity fields with `@SetFromFlag`.
+        //
+        // Returns all config keys / flags that match things in bagFlags, including duplicates.
+        // For example, if a configKey in Java is re-declared in YAML `brooklyn.parameters`,
+        // then we'll get two records.
+        //
+        // Make some effort to have these returned in the right order. That is very important
+        // because they are added to the `EntitySpec.configure(key, val)`. If there is already
+        // a key in `EntitySpec.config`, then the put will replace the value and leave the key
+        // as-is (so the default-value and description of the key will remain as whatever the
+        // first put said).
+        
+        // TODO We should remove duplicates, rather than just doing the `put` multiple times, 
+        // relying on ordering. We should also respect the ordered returned by 
+        // EntityDynamicType.getConfigKeys, which is much better (it respects `BasicConfigKeyOverwriting` 
+        // etc).
+        // 
+        // However, that is hard/fiddly because of the way a config key can be referenced by
+        // its real name or flag-name.
+        // 
+        // I wonder if this is fundamentally broken (and I really do dislike our informal use 
+        // of aliases). Consider a configKey with name A and alias B. The bagFlags could have 
+        // {A: val1, B: val2}. There is no formal definition of which takes precedence. We'll add 
+        // both to the entity's configBag, without any warning - it's up to the `config().get()` 
+        // method to then figure out what to do. It gets worse if there is also a ConfigKey with 
+        // name "B" the "val2" then applies to both!
+        //
+        // I plan to propose a change on dev@brooklyn, to replace `@SetFromFlag`!
+        
         Set<FlagConfigKeyAndValueRecord> allKeys = MutableSet.of();
-        allKeys.addAll(FlagUtils.findAllFlagsAndConfigKeys(null, spec.getType(), bagFlags));
+        allKeys.addAll(FlagUtils.findAllParameterConfigKeys(spec.getParameters(), bagFlags));
         if (spec.getImplementation() != null) {
             allKeys.addAll(FlagUtils.findAllFlagsAndConfigKeys(null, spec.getImplementation(), bagFlags));
         }
+        allKeys.addAll(FlagUtils.findAllFlagsAndConfigKeys(null, spec.getType(), bagFlags));
         for (Class<?> iface : spec.getAdditionalInterfaces()) {
             allKeys.addAll(FlagUtils.findAllFlagsAndConfigKeys(null, iface, bagFlags));
         }
-        allKeys.addAll(FlagUtils.findAllParameterConfigKeys(spec.getParameters(), bagFlags));
         return allKeys;
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/92ff8201/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/SpecParameterUnwrappingTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/SpecParameterUnwrappingTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/SpecParameterUnwrappingTest.java
index c0eb8ef..b332f8f 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/SpecParameterUnwrappingTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/SpecParameterUnwrappingTest.java
@@ -244,13 +244,16 @@ public class SpecParameterUnwrappingTest extends AbstractYamlTest {
         List<SpecParameter<?>> params = spec.getParameters();
         switch (type.getSimpleName()) {
             case "ConfigEntityForTest":
-                assertEquals(params.size(), 4);
+                // expect: own "simple"; super-type's "sample.config"; and generic "defaultDisplayName"
+                assertEquals(params.size(), 3, "params="+params);
                 break;
             case "ConfigPolicyForTest":
-                assertEquals(params.size(), 3);
+                // expect: own "simple"; and super-type's "sample.config"
+                assertEquals(params.size(), 2, "params="+params);
                 break;
             case "ConfigLocationForTest":
-                assertEquals(params.size(), 8);
+                // Expect: own "simple"; super-type's "sample.config"; and generic "parentLocation" + "spec.final" + "spec.named.name" + "spec.original" + "temporaryLocation"
+                assertEquals(params.size(), 7, "params="+params);
                 break;
         }
         assertTrue(Iterables.tryFind(params, nameEqualTo("simple")).isPresent());


[09/13] brooklyn-server git commit: BROOKLYN-345 address review comments

Posted by he...@apache.org.
BROOKLYN-345 address review comments

- fix test of catalogYamlWithDslReferenceParentDefault
- ServiceFailureDetector.lastPublished - use a real configKey
  instead of `@SetFromFlag`
- Entity memento: persist entire configKey if not same as a
  key statically defined on the entity class. Don\u2019t just use
  name-equivalence, as then couldn\u2019t change defaultVal in yawl\u2019s
  `brooklyn.parameters`.


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/a9ec838b
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/a9ec838b
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/a9ec838b

Branch: refs/heads/master
Commit: a9ec838b1957c17a75692f9e46d538cd75a93b34
Parents: dba7494
Author: Aled Sage <al...@gmail.com>
Authored: Wed Nov 16 21:50:00 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 28 21:11:48 2016 +0000

----------------------------------------------------------------------
 .../camp/brooklyn/ConfigParametersYamlTest.java |  5 ++++
 .../ServiceFailureDetectorYamlRebindTest.java   | 11 ++++----
 .../ServiceFailureDetectorYamlTest.java         | 27 ++++++++++++------
 .../mgmt/rebind/dto/BasicEntityMemento.java     | 28 ++++++++++---------
 .../policy/ha/ServiceFailureDetector.java       | 29 ++++++++++++++------
 5 files changed, 65 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a9ec838b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
index 79ab2a4..78219c6 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
@@ -133,6 +133,11 @@ public class ConfigParametersYamlTest extends AbstractYamlRebindTest {
 
         // Check config key is listed
         assertKeyEquals(entity, TestEntity.CONF_NAME.getName(), "myDescription", String.class, "myDefaultYamlVal", "myDefaultYamlVal");
+
+        // Rebind, and then check again that the config key is listed
+        Entity newApp = rebind();
+        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren());
+        assertKeyEquals(newEntity, TestEntity.CONF_NAME.getName(), "myDescription", String.class, "myDefaultYamlVal", "myDefaultYamlVal");
     }
     
     @Test

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a9ec838b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlRebindTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlRebindTest.java
index 377a2a5..d10be45 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlRebindTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlRebindTest.java
@@ -28,6 +28,7 @@ import static org.apache.brooklyn.camp.brooklyn.ServiceFailureDetectorYamlTest.s
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.rebind.RebindManager.RebindFailureMode;
+import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
@@ -57,7 +58,7 @@ public class ServiceFailureDetectorYamlRebindTest extends AbstractYamlRebindTest
     public void testRebindWhenHealthyWithDslConfig() throws Exception {
         runRebindWhenHealthy(catalogYamlWithDsl, appVersionedId);
         
-        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(app().getChildren());
+        TestEntity newEntity = (TestEntity) Iterables.find(app().getChildren(), EntityPredicates.displayNameEqualTo("targetEntity"));
         ServiceFailureDetector newEnricher = assertHasEnricher(newEntity, ServiceFailureDetector.class);
         assertEnricherConfigMatchesDsl(newEnricher);
     }
@@ -66,7 +67,7 @@ public class ServiceFailureDetectorYamlRebindTest extends AbstractYamlRebindTest
     public void testRebindWhenHealthyWithDslConfigReferenceParentDefault() throws Exception {
         runRebindWhenHealthy(catalogYamlWithDslReferenceParentDefault, appVersionedId);
         
-        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(app().getChildren());
+        TestEntity newEntity = (TestEntity) Iterables.find(app().getChildren(), EntityPredicates.displayNameEqualTo("targetEntity"));
         ServiceFailureDetector newEnricher = assertHasEnricher(newEntity, ServiceFailureDetector.class);
         assertEnricherConfigMatchesDsl(newEnricher);
     }
@@ -98,7 +99,7 @@ public class ServiceFailureDetectorYamlRebindTest extends AbstractYamlRebindTest
 
         // Rebind
         StartableApplication newApp = rebind();
-        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren());
+        TestEntity newEntity = (TestEntity) Iterables.find(newApp.getChildren(), EntityPredicates.displayNameEqualTo("targetEntity"));
         assertHasEnricher(newEntity, ServiceFailureDetector.class);
         
         // Confirm ServiceFailureDetector still functions
@@ -118,14 +119,14 @@ public class ServiceFailureDetectorYamlRebindTest extends AbstractYamlRebindTest
         Entity app = createStartWaitAndLogApplication(appYaml);
         
         // Make entity go on-fire
-        TestEntity entity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
+        TestEntity entity = (TestEntity) Iterables.find(app.getChildren(), EntityPredicates.displayNameEqualTo("targetEntity"));
         RecordingSensorEventListener<Object> listener = subscribeToHaSensors(entity);
         ServiceNotUpLogic.updateNotUpIndicator(entity, INDICATOR_KEY_1, "Simulating a problem");
         listener.assertHasEventEventually(SensorEventPredicates.sensorEqualTo(HASensors.ENTITY_FAILED));
 
         // Rebind
         StartableApplication newApp = rebind();
-        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren());
+        TestEntity newEntity = (TestEntity) Iterables.find(newApp.getChildren(), EntityPredicates.displayNameEqualTo("targetEntity"));
         assertHasEnricher(newEntity, ServiceFailureDetector.class);
         
         // Confirm ServiceFailureDetector still functions

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a9ec838b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlTest.java
index 4374c2b..b7b4ffb 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlTest.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
 import org.apache.brooklyn.core.sensor.SensorEventPredicates;
@@ -61,6 +62,7 @@ public class ServiceFailureDetectorYamlTest extends AbstractYamlTest {
             "  itemType: entity",
             "  item:",
             "    type: " + TestEntity.class.getName(),
+            "    name: targetEntity",
             "    brooklyn.enrichers:",
             "    - type: " + ServiceFailureDetector.class.getName());
 
@@ -72,6 +74,7 @@ public class ServiceFailureDetectorYamlTest extends AbstractYamlTest {
             "  item:",
             "    services:",
             "    - type: " + TestEntity.class.getName(),//FailingEntity.class.getName(),
+            "      name: targetEntity",
             "      brooklyn.parameters:",
             "      - name: custom.stabilizationDelay",
             "        type: " + Duration.class.getName(),
@@ -87,6 +90,11 @@ public class ServiceFailureDetectorYamlTest extends AbstractYamlTest {
             "          entityRecovered.stabilizationDelay: $brooklyn:config(\"custom.stabilizationDelay\")",
             "          entityFailed.republishTime: $brooklyn:config(\"custom.republishTime\")");
 
+    /*
+     * TODO Currently have to use `scopeRoot`. The brooklyn.parameter defined on the parent entity 
+     * isn't inherited, so when the child does `$brooklyn:config("custom.stabilizationDelay")` it 
+     * doesn't find a default value - we get null.
+     */
     static final String catalogYamlWithDslReferenceParentDefault = Joiner.on("\n").join(
             "brooklyn.catalog:",
             "  id: my-app",
@@ -101,14 +109,17 @@ public class ServiceFailureDetectorYamlTest extends AbstractYamlTest {
             "      type: " + Duration.class.getName(),
             "      default: 1m",
             "    services:",
-            "    - type: " + TestEntity.class.getName(),//FailingEntity.class.getName(),
+            "    - type: " + TestEntity.class.getName(),
+            "      name: ignored",
+            "    - type: " + TestEntity.class.getName(),
+            "      name: targetEntity",
             "      brooklyn.enrichers:",
             "      - type: " + ServiceFailureDetector.class.getName(),
             "        brooklyn.config:",
-            "          serviceOnFire.stabilizationDelay: $brooklyn:config(\"custom.stabilizationDelay\")",
-            "          entityFailed.stabilizationDelay: $brooklyn:config(\"custom.stabilizationDelay\")",
-            "          entityRecovered.stabilizationDelay: $brooklyn:config(\"custom.stabilizationDelay\")",
-            "          entityFailed.republishTime: $brooklyn:config(\"custom.republishTime\")");
+            "          serviceOnFire.stabilizationDelay: $brooklyn:scopeRoot().config(\"custom.stabilizationDelay\")",
+            "          entityFailed.stabilizationDelay: $brooklyn:scopeRoot().config(\"custom.stabilizationDelay\")",
+            "          entityRecovered.stabilizationDelay: $brooklyn:scopeRoot().config(\"custom.stabilizationDelay\")",
+            "          entityFailed.republishTime: $brooklyn:scopeRoot().config(\"custom.republishTime\")");
 
     @Test
     public void testDefaults() throws Exception {
@@ -119,7 +130,7 @@ public class ServiceFailureDetectorYamlTest extends AbstractYamlTest {
     public void testWithDslConfig() throws Exception {
         Entity app = runTest(catalogYamlWithDsl, appVersionedId);
         
-        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
+        TestEntity newEntity = (TestEntity) Iterables.find(app.getChildren(), EntityPredicates.displayNameEqualTo("targetEntity"));
         ServiceFailureDetector newEnricher = assertHasEnricher(newEntity, ServiceFailureDetector.class);
         assertEnricherConfigMatchesDsl(newEnricher);
     }
@@ -128,7 +139,7 @@ public class ServiceFailureDetectorYamlTest extends AbstractYamlTest {
     public void testWithDslConfigReferenceParentDefault() throws Exception {
         Entity app = runTest(catalogYamlWithDslReferenceParentDefault, appVersionedId);
         
-        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
+        TestEntity newEntity = (TestEntity) Iterables.find(app.getChildren(), EntityPredicates.displayNameEqualTo("targetEntity"));
         ServiceFailureDetector newEnricher = assertHasEnricher(newEntity, ServiceFailureDetector.class);
         assertEnricherConfigMatchesDsl(newEnricher);
     }
@@ -140,7 +151,7 @@ public class ServiceFailureDetectorYamlTest extends AbstractYamlTest {
                 "services:",
                 "- type: " + appId);
         Entity app = createStartWaitAndLogApplication(appYaml);
-        TestEntity entity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
+        TestEntity entity = (TestEntity) Iterables.find(app.getChildren(), EntityPredicates.displayNameEqualTo("targetEntity"));
         assertHasEnricher(entity, ServiceFailureDetector.class);
         
         // Confirm ServiceFailureDetector triggers event

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a9ec838b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
index a150fd5..9966c95 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
@@ -150,29 +150,28 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
         staticConfigKeys = getStaticConfigKeys();
         staticSensorKeys = getStaticSensorKeys();
         
-        if (configByKey!=null) {
-            configKeys = Maps.newLinkedHashMap();
-            config = Maps.newLinkedHashMap();
-            
+        configKeys = Maps.newLinkedHashMap();
+        config = Maps.newLinkedHashMap();
+        
+        if (allConfigKeys != null) {
             for (ConfigKey<?> key : allConfigKeys) {
-                if (!key.equals(staticConfigKeys.get(key.getName()))) {
+                if (key != staticConfigKeys.get(key.getName())) {
                     configKeys.put(key.getName(), key);
                 }
             }
+        }
+        if (configByKey != null) {
             for (Map.Entry<ConfigKey<?>, Object> entry : configByKey.entrySet()) {
                 ConfigKey<?> key = entry.getKey();
-                if (!configKeys.containsKey(key) && !key.equals(staticConfigKeys.get(key.getName()))) {
+                if (!configKeys.containsKey(key) && key != staticConfigKeys.get(key.getName())) {
                     configKeys.put(key.getName(), key);
                 }
                 config.put(key.getName(), entry.getValue());
             }
-            configKeys = toPersistedMap(configKeys);
-            config = toPersistedMap(config);
         }
-        if (configUnmatched!=null) {
-            if (config == null) config = Maps.newLinkedHashMap();
+        
+        if (configUnmatched != null) {
             config.putAll(configUnmatched);
-            config = toPersistedMap(config);
         }
         if (attributesByKey!=null) {
             attributeKeys = Maps.newLinkedHashMap();
@@ -183,9 +182,12 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
                     attributeKeys.put(key.getName(), key);
                 attributes.put(key.getName(), entry.getValue());
             }
-            attributeKeys = toPersistedMap(attributeKeys);
-            attributes = toPersistedMap(attributes);
         }
+        
+        configKeys = toPersistedMap(configKeys);
+        config = toPersistedMap(config);
+        attributeKeys = toPersistedMap(attributeKeys);
+        attributes = toPersistedMap(attributes);
     }
 
     protected synchronized Map<String, ConfigKey<?>> getStaticConfigKeys() {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a9ec838b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
index cba2abd..5f8ae3d 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ComputeServic
 import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy;
 import org.apache.brooklyn.policy.ha.HASensors.FailureDescriptor;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
@@ -114,8 +115,11 @@ public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceStat
      * (we'll only publish again if we are in a different state from before Brooklyn was last
      * shutdown).
      */
-    @SetFromFlag
-    protected LastPublished lastPublished = LastPublished.NONE;
+    public static final ConfigKey<LastPublished> LAST_PUBLISHED = ConfigKeys.newConfigKey(
+            LastPublished.class,
+            "lastPublished",
+            "Indicates the last published event (entity 'failed', 'recovered', or none); used like an attribute (i.e. expect to be set on-the-fly)",
+            LastPublished.NONE);
 
     protected Long firstUpTime;
     
@@ -139,6 +143,15 @@ public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceStat
      */
     private final Object mutex = new Object();
     
+    @Override
+    protected <T> void doReconfigureConfig(ConfigKey<T> key, T val) {
+        if (key.equals(LAST_PUBLISHED)) {
+            // find to modify this on-the-fly; no additional work required
+        } else {
+            super.doReconfigureConfig(key, val);
+        }
+    }
+    
     public ServiceFailureDetector() {
         this(new ConfigBag());
     }
@@ -172,7 +185,7 @@ public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceStat
 
         synchronized (mutex) {
             if (state.orNull() == Lifecycle.ON_FIRE) {
-                if (lastPublished == LastPublished.FAILED) {
+                if (config().get(LAST_PUBLISHED) == LastPublished.FAILED) {
                     if (currentRecoveryStartTime != null) {
                         if (LOG.isDebugEnabled()) LOG.debug("{} health-check for {}, component was recovering, now failing: {}", new Object[] {this, entity, getExplanation(state)});
                         currentRecoveryStartTime = null;
@@ -198,7 +211,7 @@ public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceStat
                 publishEntityRecoveredTime = null;
                 
             } else if (state.orNull() == Lifecycle.RUNNING) {
-                if (lastPublished == LastPublished.FAILED) {
+                if (config().get(LAST_PUBLISHED) == LastPublished.FAILED) {
                     if (currentRecoveryStartTime == null) {
                         if (LOG.isDebugEnabled()) LOG.debug("{} health-check for {}, component now recovering: {}", new Object[] {this, entity, getExplanation(state)});
                         currentRecoveryStartTime = now;
@@ -235,9 +248,8 @@ public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceStat
                         publishEntityFailedTime = now + republishDelay.toMilliseconds();
                         recomputeIn = Math.min(recomputeIn, republishDelay.toMilliseconds());
                     }
-                    lastPublished = LastPublished.FAILED;
                     entity.sensors().emit(HASensors.ENTITY_FAILED, new HASensors.FailureDescriptor(entity, getFailureDescription(now)));
-                    requestPersist();
+                    config().set(LAST_PUBLISHED, LastPublished.FAILED);
                 } else {
                     recomputeIn = Math.min(recomputeIn, delayBeforeCheck);
                 }
@@ -247,9 +259,8 @@ public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceStat
                     if (LOG.isDebugEnabled()) LOG.debug("{} publishing recovered (state={}; currentRecoveryStartTime={}; now={}", 
                             new Object[] {this, state, Time.makeDateString(currentRecoveryStartTime), Time.makeDateString(now)});
                     publishEntityRecoveredTime = null;
-                    lastPublished = LastPublished.RECOVERED;
                     entity.sensors().emit(HASensors.ENTITY_RECOVERED, new HASensors.FailureDescriptor(entity, null));
-                    requestPersist();
+                    config().set(LAST_PUBLISHED, LastPublished.RECOVERED);
                 } else {
                     recomputeIn = Math.min(recomputeIn, delayBeforeCheck);
                 }
@@ -283,7 +294,7 @@ public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceStat
                     "currentFailurePeriod=%s; currentRecoveryPeriod=%s",
                 entity.getLocations(), 
                 (state.orNull() != null ? state : "<unreported>"),
-                lastPublished,
+                config().get(LAST_PUBLISHED),
                 Time.makeDateString(System.currentTimeMillis()),
                 (currentFailureStartTime != null ? getTimeStringSince(currentFailureStartTime) : "<none>") + " (stabilization "+Time.makeTimeStringRounded(serviceFailedStabilizationDelay) + ")",
                 (currentRecoveryStartTime != null ? getTimeStringSince(currentRecoveryStartTime) : "<none>") + " (stabilization "+Time.makeTimeStringRounded(serviceRecoveredStabilizationDelay) + ")");


[06/13] brooklyn-server git commit: BROOKLYN-345: add (failing) tests for rebind

Posted by he...@apache.org.
BROOKLYN-345: add (failing) tests for rebind


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/b97cd178
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/b97cd178
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/b97cd178

Branch: refs/heads/master
Commit: b97cd17839d8414fb70339de37417abc0d3ff574
Parents: c856cd1
Author: Aled Sage <al...@gmail.com>
Authored: Wed Nov 16 09:58:08 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 28 21:11:48 2016 +0000

----------------------------------------------------------------------
 .../camp/brooklyn/AbstractYamlRebindTest.java   |   1 +
 .../camp/brooklyn/ConfigParametersYamlTest.java |  87 ++++++++---
 .../camp/brooklyn/DslAndRebindYamlTest.java     |  18 +++
 .../ServiceFailureDetectorYamlRebindTest.java   | 147 +++++++++++++++++++
 .../rebind/RecordingRebindExceptionHandler.java |  33 ++++-
 5 files changed, 258 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b97cd178/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
index 5eae76c..2ba96e2 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
@@ -82,6 +82,7 @@ public class AbstractYamlRebindTest extends RebindTestFixture<StartableApplicati
         }
     }
 
+    @Override
     protected StartableApplication rebind(RebindOptions options) throws Exception {
         StartableApplication result = super.rebind(options);
         if (launcher != null) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b97cd178/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
index 7d6828a..2f655c6 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
@@ -55,7 +55,7 @@ import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 
-public class ConfigParametersYamlTest extends AbstractYamlTest {
+public class ConfigParametersYamlTest extends AbstractYamlRebindTest {
     @SuppressWarnings("unused")
     private static final Logger LOG = LoggerFactory.getLogger(ConfigParametersYamlTest.class);
 
@@ -77,6 +77,40 @@ public class ConfigParametersYamlTest extends AbstractYamlTest {
     }
     
     @Test
+    public void testConfigParameterWithOverriddenValueListedInType() throws Exception {
+        addCatalogItems(
+                "brooklyn.catalog:",
+                "  itemType: entity",
+                "  items:",
+                "  - id: entity-with-keys",
+                "    item:",
+                "      type: "+TestEntity.class.getName(),
+                "      brooklyn.parameters:",
+                "      - name: testConfigParametersListedInType.mykey",
+                "        description: myDescription",
+                "        type: String",
+                "        default: myDefaultVal",
+                "      brooklyn.config:",
+                "        testConfigParametersListedInType.mykey: myOverridingVal");
+        
+        String yaml = Joiner.on("\n").join(
+                "services:",
+                "- type: entity-with-keys");
+        
+        Entity app = createStartWaitAndLogApplication(yaml);
+        TestEntity entity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
+
+        // Check config key is listed
+        assertKeyEquals(entity, "testConfigParametersListedInType.mykey", "myDescription", String.class, "myDefaultVal", "myOverridingVal");
+
+        // Rebind, and then check again that the config key is listed
+        Entity newApp = rebind();
+        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren());
+        assertKeyEquals(newEntity, "testConfigParametersListedInType.mykey", "myDescription", String.class, "myDefaultVal", "myOverridingVal");
+    }
+    
+
+    @Test
     public void testConfigParametersListedInType() throws Exception {
         addCatalogItems(
                 "brooklyn.catalog:",
@@ -100,19 +134,17 @@ public class ConfigParametersYamlTest extends AbstractYamlTest {
         TestEntity entity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
 
         // Check config key is listed
-        ConfigKey<?> key = entity.getEntityType().getConfigKey("testConfigParametersListedInType.mykey");
-        assertNotNull(key);
-        assertEquals(key.getName(), "testConfigParametersListedInType.mykey");
-        assertEquals(key.getDescription(), "myDescription");
-        assertEquals(key.getType(), Map.class);
-        assertEquals(key.getDefaultValue(), ImmutableMap.of("myDefaultKey", "myDefaultVal"));
-        
-        // Check get default value
-        assertEquals(entity.config().get(key), ImmutableMap.of("myDefaultKey", "myDefaultVal"));
+        Map<?,?> expectedVal = ImmutableMap.of("myDefaultKey", "myDefaultVal");
+        assertKeyEquals(entity, "testConfigParametersListedInType.mykey", "myDescription", Map.class, expectedVal, expectedVal);
+
+        // Rebind, and then check again that the config key is listed
+        Entity newApp = rebind();
+        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren());
+        assertKeyEquals(newEntity, "testConfigParametersListedInType.mykey", "myDescription", Map.class, expectedVal, expectedVal);
     }
     
     /**
-     * See comment in testConfigParametersAtRootListedInTemplateSingleEntity for why we have two 
+     * See comment in testConfigParametersAtRootListedInTemplateSingleEntity for why we have two. 
      * Note that (surprisingly!) it's very important that there are two entities listed under 
      * "services". If there is just one, then the BasicApplication created to wrap it will not 
      * have the key. Instead, the single child will have the key. This is because the top-level 
@@ -144,11 +176,11 @@ public class ConfigParametersYamlTest extends AbstractYamlTest {
         
         Entity app = createStartWaitAndLogApplication(yaml);
         
-        ConfigKey<?> key = app.getEntityType().getConfigKey("test.parameter");
-        assertNotNull(key, "No key 'test.parameter'; keys="+app.getEntityType().getConfigKeys());
-        assertEquals(key.getDescription(), "myDescription");
-        assertEquals(key.getType(), String.class);
-        assertEquals(key.getDefaultValue(), "myDefaultParamVal");
+        assertKeyEquals(app, "test.parameter", "myDescription", String.class, "myDefaultParamVal", "myDefaultParamVal");
+
+        // After rebind, check config key is listed
+        newApp = rebind();
+        assertKeyEquals(newApp, "test.parameter", "myDescription", String.class, "myDefaultParamVal", "myDefaultParamVal");
     }
 
     /**
@@ -178,11 +210,12 @@ public class ConfigParametersYamlTest extends AbstractYamlTest {
         Entity app = createStartWaitAndLogApplication(yaml);
         TestEntity entity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
         
-        ConfigKey<?> key = entity.getEntityType().getConfigKey("test.parameter");
-        assertNotNull(key, "No key 'test.parameter'; keys="+entity.getEntityType().getConfigKeys());
-        assertEquals(key.getDescription(), "myDescription");
-        assertEquals(key.getType(), String.class);
-        assertEquals(key.getDefaultValue(), "myDefaultParamVal");
+        assertKeyEquals(entity, "test.parameter", "myDescription", String.class, "myDefaultParamVal", "myDefaultParamVal");
+        
+        // After rebind, check config key is listed
+        newApp = rebind();
+        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren());
+        assertKeyEquals(newEntity, "test.parameter", "myDescription", String.class, "myDefaultParamVal", "myDefaultParamVal");
     }
 
     @Test
@@ -614,4 +647,16 @@ public class ConfigParametersYamlTest extends AbstractYamlTest {
         assertEquals(entity.config().get(ConfigKeys.newConfigKey(Object.class, "my.param.key")), PortRanges.fromInteger(1234));
         assertEquals(entity.sensors().get(Sensors.newSensor(Object.class, "my.param.key")), 1234);
     }
+
+    protected <T> void assertKeyEquals(Entity entity, String keyName, String expectedDescription, Class<T> expectedType, T expectedDefaultVal, T expectedEntityVal) {
+        ConfigKey<?> key = entity.getEntityType().getConfigKey(keyName);
+        assertNotNull(key, "No key '"+keyName+"'; keys="+entity.getEntityType().getConfigKeys());
+
+        assertEquals(key.getName(), keyName);
+        assertEquals(key.getDescription(), expectedDescription);
+        assertEquals(key.getType(), expectedType);
+        assertEquals(key.getDefaultValue(), expectedDefaultVal);
+        
+        assertEquals(entity.config().get(key), expectedEntityVal);
+    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b97cd178/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
index 91da883..9770338 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
@@ -386,6 +386,7 @@ public class DslAndRebindYamlTest extends AbstractYamlRebindTest {
         Entity e2 = rebind(testEntity);
 
         Assert.assertEquals(getConfigInTask(e2, TestEntity.CONF_NAME), "bar");
+        Assert.assertEquals(e2.getConfig(TestEntity.CONF_NAME), "bar");
     }
 
     private Entity entityWithConfigFromRoot() throws Exception {
@@ -397,6 +398,23 @@ public class DslAndRebindYamlTest extends AbstractYamlRebindTest {
                 "  foo: bar");
     }
 
+    @Test
+    public void testDslConfigWithBrooklynParameterDefault() throws Exception {
+        Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
+                "  id: x",
+                "  brooklyn.parameters:",
+                "  - name: test.param",
+                "    type: String",
+                "    default: myDefaultVal",
+                "  brooklyn.config:",
+                "    test.confName: $brooklyn:config(\"test.param\")");
+        Assert.assertEquals(getConfigInTask(testEntity, TestEntity.CONF_NAME), "myDefaultVal");
+        Assert.assertEquals(testEntity.config().get(TestEntity.CONF_NAME), "myDefaultVal");
+        
+        Entity e2 = rebind(testEntity);
+        Assert.assertEquals(getConfigInTask(e2, TestEntity.CONF_NAME), "myDefaultVal");
+        Assert.assertEquals(e2.config().get(TestEntity.CONF_NAME), "myDefaultVal");
+    }
 
     @Test
     public void testDslFormatString() throws Exception {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b97cd178/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlRebindTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlRebindTest.java
new file mode 100644
index 0000000..377a2a5
--- /dev/null
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ServiceFailureDetectorYamlRebindTest.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.camp.brooklyn;
+
+import static org.apache.brooklyn.camp.brooklyn.ServiceFailureDetectorYamlTest.appVersionedId;
+import static org.apache.brooklyn.camp.brooklyn.ServiceFailureDetectorYamlTest.assertEnricherConfigMatchesDsl;
+import static org.apache.brooklyn.camp.brooklyn.ServiceFailureDetectorYamlTest.assertHasEnricher;
+import static org.apache.brooklyn.camp.brooklyn.ServiceFailureDetectorYamlTest.catalogYamlSimple;
+import static org.apache.brooklyn.camp.brooklyn.ServiceFailureDetectorYamlTest.catalogYamlWithDsl;
+import static org.apache.brooklyn.camp.brooklyn.ServiceFailureDetectorYamlTest.catalogYamlWithDslReferenceParentDefault;
+import static org.apache.brooklyn.camp.brooklyn.ServiceFailureDetectorYamlTest.subscribeToHaSensors;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.rebind.RebindManager.RebindFailureMode;
+import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
+import org.apache.brooklyn.core.entity.StartableApplication;
+import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
+import org.apache.brooklyn.core.mgmt.rebind.RebindExceptionHandlerImpl;
+import org.apache.brooklyn.core.mgmt.rebind.RebindOptions;
+import org.apache.brooklyn.core.mgmt.rebind.RecordingRebindExceptionHandler;
+import org.apache.brooklyn.core.sensor.SensorEventPredicates;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.policy.ha.HASensors;
+import org.apache.brooklyn.policy.ha.ServiceFailureDetector;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
+
+@Test
+public class ServiceFailureDetectorYamlRebindTest extends AbstractYamlRebindTest {
+    
+    final static String INDICATOR_KEY_1 = "test-indicator-1";
+
+    @Test
+    public void testRebindWhenHealthy() throws Exception {
+        runRebindWhenHealthy(catalogYamlSimple, appVersionedId);
+    }
+    
+    @Test
+    public void testRebindWhenHealthyWithDslConfig() throws Exception {
+        runRebindWhenHealthy(catalogYamlWithDsl, appVersionedId);
+        
+        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(app().getChildren());
+        ServiceFailureDetector newEnricher = assertHasEnricher(newEntity, ServiceFailureDetector.class);
+        assertEnricherConfigMatchesDsl(newEnricher);
+    }
+
+    @Test
+    public void testRebindWhenHealthyWithDslConfigReferenceParentDefault() throws Exception {
+        runRebindWhenHealthy(catalogYamlWithDslReferenceParentDefault, appVersionedId);
+        
+        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(app().getChildren());
+        ServiceFailureDetector newEnricher = assertHasEnricher(newEntity, ServiceFailureDetector.class);
+        assertEnricherConfigMatchesDsl(newEnricher);
+    }
+    
+    @Test
+    public void testRebindWhenHasNotUpIndicator() throws Exception {
+        runRebindWhenNotUp(catalogYamlSimple, appVersionedId);
+    }
+    
+    // See https://issues.apache.org/jira/browse/BROOKLYN-345
+    @Test
+    public void testRebinWhenHasNotUpIndicatorWithDslConfig() throws Exception {
+        runRebindWhenNotUp(catalogYamlWithDsl, appVersionedId);
+    }
+    
+    // See https://issues.apache.org/jira/browse/BROOKLYN-345
+    @Test
+    public void testRebindWhenHasNotUpIndicatorWithDslConfigReferenceParentDefault() throws Exception {
+        runRebindWhenNotUp(catalogYamlWithDslReferenceParentDefault, appVersionedId);
+    }
+    
+    protected void runRebindWhenHealthy(String catalogYaml, String appId) throws Exception {
+        addCatalogItems(catalogYaml);
+
+        String appYaml = Joiner.on("\n").join(
+                "services:",
+                "- type: " + appId);
+        createStartWaitAndLogApplication(appYaml);
+
+        // Rebind
+        StartableApplication newApp = rebind();
+        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren());
+        assertHasEnricher(newEntity, ServiceFailureDetector.class);
+        
+        // Confirm ServiceFailureDetector still functions
+        RecordingSensorEventListener<Object> listener = subscribeToHaSensors(newEntity);
+        
+        ServiceNotUpLogic.updateNotUpIndicator(newEntity, INDICATOR_KEY_1, "Simulate a problem");
+        listener.assertHasEventEventually(SensorEventPredicates.sensorEqualTo(HASensors.ENTITY_FAILED));
+        listener.assertEventCount(1);
+    }
+
+    protected void runRebindWhenNotUp(String catalogYaml, String appId) throws Exception {
+        addCatalogItems(catalogYaml);
+
+        String appYaml = Joiner.on("\n").join(
+                "services:",
+                "- type: " + appId);
+        Entity app = createStartWaitAndLogApplication(appYaml);
+        
+        // Make entity go on-fire
+        TestEntity entity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
+        RecordingSensorEventListener<Object> listener = subscribeToHaSensors(entity);
+        ServiceNotUpLogic.updateNotUpIndicator(entity, INDICATOR_KEY_1, "Simulating a problem");
+        listener.assertHasEventEventually(SensorEventPredicates.sensorEqualTo(HASensors.ENTITY_FAILED));
+
+        // Rebind
+        StartableApplication newApp = rebind();
+        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren());
+        assertHasEnricher(newEntity, ServiceFailureDetector.class);
+        
+        // Confirm ServiceFailureDetector still functions
+        RecordingSensorEventListener<Object> newListener = subscribeToHaSensors(newEntity);
+        
+        ServiceNotUpLogic.clearNotUpIndicator(newEntity, INDICATOR_KEY_1);
+        newListener.assertHasEventEventually(SensorEventPredicates.sensorEqualTo(HASensors.ENTITY_RECOVERED));
+        newListener.assertEventCount(1);
+    }
+    
+    @Override
+    protected StartableApplication rebind() throws Exception {
+        RecordingRebindExceptionHandler exceptionHandler = new RecordingRebindExceptionHandler(RebindExceptionHandlerImpl.builder()
+                .addPolicyFailureMode(RebindFailureMode.FAIL_AT_END)
+                .loadPolicyFailureMode(RebindFailureMode.FAIL_AT_END)
+                .danglingRefFailureMode(RebindFailureMode.FAIL_AT_END));
+        return rebind(RebindOptions.create().exceptionHandler(exceptionHandler));
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b97cd178/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RecordingRebindExceptionHandler.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RecordingRebindExceptionHandler.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RecordingRebindExceptionHandler.java
index 6d27fc7..b94970d 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RecordingRebindExceptionHandler.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RecordingRebindExceptionHandler.java
@@ -22,28 +22,35 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mgmt.rebind.RebindManager;
 import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.objs.BrooklynObjectType;
-import org.apache.brooklyn.core.mgmt.rebind.RebindExceptionHandlerImpl;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.sensor.Enricher;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
 public class RecordingRebindExceptionHandler extends RebindExceptionHandlerImpl {
 
-    protected final List<Exception> loadMementoFailures = Lists.newArrayList();
-    protected final Map<String, Exception> createFailures = Maps.newLinkedHashMap();
-    protected final Map<BrooklynObject, Exception> rebindFailures = Maps.newLinkedHashMap();
-    protected final Map<BrooklynObject, Exception> manageFailures = Maps.newLinkedHashMap();
-    protected final Map<String, Exception> notFoundFailures = Maps.newLinkedHashMap();
-    protected Exception failed;
+    public final List<Exception> loadMementoFailures = Lists.newArrayList();
+    public final Map<String, Exception> createFailures = Maps.newLinkedHashMap();
+    public final Map<BrooklynObject, Exception> rebindFailures = Maps.newLinkedHashMap();
+    public final Map<BrooklynObject, Exception> manageFailures = Maps.newLinkedHashMap();
+    public final Map<BrooklynObject, Exception> addFailures = Maps.newLinkedHashMap();
+    public final Map<String, Exception> notFoundFailures = Maps.newLinkedHashMap();
+    public Exception failed;
     
     public RecordingRebindExceptionHandler(RebindManager.RebindFailureMode danglingRefFailureMode, RebindManager.RebindFailureMode rebindFailureMode) {
         super(builder().danglingRefFailureMode(danglingRefFailureMode).rebindFailureMode(rebindFailureMode));
     }
 
+    public RecordingRebindExceptionHandler(Builder builder) {
+        super(builder);
+    }
+
     @Override
     public void onLoadMementoFailed(BrooklynObjectType type, String msg, Exception e) {
         loadMementoFailures.add(new IllegalStateException("problem loading "+type.toCamelCase()+" memento: "+msg, e));
@@ -89,4 +96,16 @@ public class RecordingRebindExceptionHandler extends RebindExceptionHandlerImpl
         failed = e;
         return super.onFailed(e);
     }
+    
+    @Override
+    public void onAddEnricherFailed(EntityLocal entity, Enricher enricher, Exception e) {
+        addFailures.put(enricher, e);
+        super.onAddEnricherFailed(entity, enricher, e);
+    }
+    
+    @Override
+    public void onAddPolicyFailed(EntityLocal entity, Policy policy, Exception e) {
+        addFailures.put(policy, e);
+        super.onAddPolicyFailed(entity, policy, e);
+    }
 }