You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sj...@apache.org on 2016/07/13 17:29:44 UTC
[4/5] brooklyn-server git commit: Add RelativeEntityTestCaseImpl
Add RelativeEntityTestCaseImpl
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/07942b12
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/07942b12
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/07942b12
Branch: refs/heads/master
Commit: 07942b12168c591fe2a0b1cd1c791c36e5f1afc5
Parents: 0c0ec60
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Mon Jun 20 18:45:50 2016 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Wed Jul 6 12:02:07 2016 +0100
----------------------------------------------------------------------
.../brooklyn/spi/dsl/methods/DslComponent.java | 14 +-
.../test/framework/RelativeEntityTestCase.java | 65 +++++++++
.../framework/RelativeEntityTestCaseImpl.java | 144 +++++++++++++++++++
.../framework/RelativeEntityTestCaseTest.java | 135 +++++++++++++++++
4 files changed, 356 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/07942b12/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
index cfb343f..b02f736 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
@@ -61,14 +61,24 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
private final DslComponent scopeComponent;
private final Scope scope;
+ /**
+ * Resolve componentId in the {@link Scope#GLOBAL} scope.
+ */
public DslComponent(String componentId) {
this(Scope.GLOBAL, componentId);
}
-
+
+ /**
+ * Resolve componentId in scope relative to the current
+ * {@link BrooklynTaskTags#getTargetOrContextEntity) target or context} entity.
+ */
public DslComponent(Scope scope, String componentId) {
this(null, scope, componentId);
}
-
+
+ /**
+ * Resolve componentId in scope relative to scopeComponent.
+ */
public DslComponent(DslComponent scopeComponent, Scope scope, String componentId) {
Preconditions.checkNotNull(scope, "scope");
this.scopeComponent = scopeComponent;
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/07942b12/test-framework/src/main/java/org/apache/brooklyn/test/framework/RelativeEntityTestCase.java
----------------------------------------------------------------------
diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/RelativeEntityTestCase.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/RelativeEntityTestCase.java
new file mode 100644
index 0000000..3796bf4
--- /dev/null
+++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/RelativeEntityTestCase.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.test.framework;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
+
+import com.google.common.base.Predicates;
+
+/**
+ * A test case that resolves target ID relative to an anchor entity.
+ * <p>
+ * For example, to run tests against a named child of an entity:
+ * <pre>
+ * services
+ * - id: app
+ * brooklyn.children:
+ * id: child-id
+ * - id: test-case
+ * brooklyn.config:
+ * anchor: $brooklyn:component("app").descendant("child-id")
+ * </pre>
+ * The anchor entity is resolved from the <code>anchor</code>, <code>target</code> or
+ * <code>targetId</code>, in order of preference. The latter two are useful when using
+ * the test with with entities like {@link LoopOverGroupMembersTestCase}. Values for
+ * <code>target</code> will be overwritten with the resolved entity so child test
+ * cases work as expected.
+ */
+@ImplementedBy(RelativeEntityTestCaseImpl.class)
+public interface RelativeEntityTestCase extends TargetableTestComponent {
+
+ AttributeSensorAndConfigKey<Entity, Entity> ANCHOR = ConfigKeys.newSensorAndConfigKey(Entity.class,
+ "anchor",
+ "Entity from which component should be resolved.");
+
+ ConfigKey<DslComponent> COMPONENT = ConfigKeys.builder(DslComponent.class)
+ .name("component")
+ .description("The component to resolve against target")
+ .constraint(Predicates.<DslComponent>notNull())
+ .build();
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/07942b12/test-framework/src/main/java/org/apache/brooklyn/test/framework/RelativeEntityTestCaseImpl.java
----------------------------------------------------------------------
diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/RelativeEntityTestCaseImpl.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/RelativeEntityTestCaseImpl.java
new file mode 100644
index 0000000..ea78e7b
--- /dev/null
+++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/RelativeEntityTestCaseImpl.java
@@ -0,0 +1,144 @@
+/*
+ * 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.test.framework;
+
+import java.util.Collection;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+public class RelativeEntityTestCaseImpl extends TargetableTestComponentImpl implements RelativeEntityTestCase {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RelativeEntityTestCaseImpl.class);
+
+ @Override
+ public Entity resolveTarget() {
+ Entity anchor = config().get(ANCHOR);
+ if (anchor == null) {
+ anchor = super.resolveTarget();
+ }
+ if (anchor == null) {
+ throw new IllegalArgumentException("No anchor entity found for " + this);
+ }
+ sensors().set(ANCHOR, anchor);
+ Maybe<Object> component = config().getRaw(COMPONENT);
+ if (component.isAbsentOrNull()) {
+ throw new IllegalArgumentException("No component found for " + this);
+ } else if (!(component.get() instanceof DslComponent)) {
+ throw new IllegalArgumentException("Expected DslComponent value for component, found " + component.get());
+ }
+ DslComponent finder = DslComponent.class.cast(component.get());
+ Task<Entity> task = Entities.submit(anchor, finder);
+ return task.getUnchecked();
+ }
+
+ @Override
+ public void start(Collection<? extends Location> locations) {
+ sensors().set(Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STARTING);
+
+ Entity target = resolveTarget();
+ if (target == null) {
+ LOG.debug("Tasks NOT successfully run. RelativeEntityTestCaseImpl target unset");
+ setServiceState(false, Lifecycle.ON_FIRE);
+ return;
+ }
+ config().set(BaseTest.TARGET_ENTITY, target);
+
+ boolean success = true;
+ try {
+ for (Entity child : getChildren()) {
+ if (child instanceof Startable) {
+ Startable test = Startable.class.cast(child);
+ test.start(locations);
+ if (Lifecycle.RUNNING.equals(child.sensors().get(Attributes.SERVICE_STATE_ACTUAL))) {
+ LOG.debug("Task of {} successfully run, targeting {}", this, target);
+ } else {
+ LOG.warn("Problem in child test-case of {}, targeting {}", this, target);
+ success = false;
+ }
+ } else {
+ LOG.info("Ignored child of {} that is not Startable: {}", this, child);
+ }
+ if (!success) {
+ break;
+ }
+ }
+ } catch (Throwable t) {
+ Exceptions.propagateIfFatal(t);
+ LOG.warn("Problem in child test-case of " + this + ", targeting " + target, t);
+ success = false;
+ }
+
+ if (success) {
+ LOG.debug("Tasks successfully run. Update state of {} to RUNNING.", this);
+ setServiceState(true, Lifecycle.RUNNING);
+ } else {
+ LOG.debug("Tasks NOT successfully run. Update state of {} to ON_FIRE.", this);
+ setServiceState(false, Lifecycle.ON_FIRE);
+ }
+ }
+
+ @Override
+ public void stop() {
+ sensors().set(Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STOPPING);
+ try {
+ for (Entity child : this.getChildren()) {
+ if (child instanceof Startable) ((Startable) child).stop();
+ }
+ LOG.debug("Tasks successfully run. Update state of {} to STOPPED.", this);
+ setServiceState(false, Lifecycle.STOPPED);
+ } catch (Throwable t) {
+ LOG.debug("Tasks NOT successfully run. Update state of {} to ON_FIRE.", this);
+ setServiceState(false, Lifecycle.ON_FIRE);
+ throw Exceptions.propagate(t);
+ }
+ }
+
+ @Override
+ public void restart() {
+ final Collection<Location> locations = Lists.newArrayList(getLocations());
+ stop();
+ start(locations);
+ }
+
+ /**
+ * Sets the state of the Entity. Useful so that the GUI shows the correct icon.
+ *
+ * @param serviceUpState Whether or not the entity is up.
+ * @param serviceStateActual The actual state of the entity.
+ */
+ private void setServiceState(final boolean serviceUpState, final Lifecycle serviceStateActual) {
+ sensors().set(SERVICE_UP, serviceUpState);
+ sensors().set(Attributes.SERVICE_STATE_ACTUAL, serviceStateActual);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/07942b12/test-framework/src/test/java/org/apache/brooklyn/test/framework/RelativeEntityTestCaseTest.java
----------------------------------------------------------------------
diff --git a/test-framework/src/test/java/org/apache/brooklyn/test/framework/RelativeEntityTestCaseTest.java b/test-framework/src/test/java/org/apache/brooklyn/test/framework/RelativeEntityTestCaseTest.java
new file mode 100644
index 0000000..c35b265
--- /dev/null
+++ b/test-framework/src/test/java/org/apache/brooklyn/test/framework/RelativeEntityTestCaseTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.test.framework;
+
+import static org.apache.brooklyn.test.Asserts.assertTrue;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityInitializer;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
+import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.sensor.StaticSensor;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.entity.group.Cluster;
+import org.apache.brooklyn.entity.group.DynamicCluster;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class RelativeEntityTestCaseTest extends BrooklynAppUnitTestSupport {
+
+ @Test
+ public void testParentAndChildScope() {
+ TestEntity parent = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+ .configure(BrooklynCampConstants.PLAN_ID, "parent-plan"));
+ TestEntity child = parent.addChild(EntitySpec.create(TestEntity.class)
+ .configure(BrooklynCampConstants.PLAN_ID, "child-plan"));
+
+ parent.sensors().set(TestEntity.NAME, "parent");
+ child.sensors().set(TestEntity.NAME, "child");
+
+ app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+ TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class)
+ .child(relativeEntityTestCaseEntitySpec(parent, "child-plan", DslComponent.Scope.CHILD, "child"))
+ .child(relativeEntityTestCaseEntitySpec(child, "parent-plan", DslComponent.Scope.PARENT, "parent")));
+
+ testCase.start(app.getLocations());
+ assertTrue(testCase.sensors().get(Attributes.SERVICE_UP), "Test case did not pass: " + testCase);
+ }
+
+ @Test
+ public void testSiblingScope() {
+ TestEntity brother = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+ .configure(BrooklynCampConstants.PLAN_ID, "brother-plan"));
+ TestEntity sister = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+ .configure(BrooklynCampConstants.PLAN_ID, "sister-plan"));
+
+ brother.sensors().set(TestEntity.NAME, "brother");
+ sister.sensors().set(TestEntity.NAME, "sister");
+
+ app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+ TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class)
+ .child(relativeEntityTestCaseEntitySpec(brother, "sister-plan", DslComponent.Scope.SIBLING, "sister"))
+ .child(relativeEntityTestCaseEntitySpec(sister, "brother-plan", DslComponent.Scope.SIBLING, "brother")));
+
+ testCase.start(app.getLocations());
+ assertTrue(testCase.sensors().get(Attributes.SERVICE_UP), "Test case did not pass: " + testCase);
+ }
+
+ @Test
+ public void testCombinationWithLoopOverGroupMembersTest() {
+ final String sensorName = TestEntity.NAME.getName();
+ final String sensorValue = "test-sensor-value";
+ EntityInitializer staticSensor = new StaticSensor<>(ConfigBag.newInstance(ImmutableMap.of(
+ StaticSensor.SENSOR_NAME, sensorName,
+ StaticSensor.STATIC_VALUE, sensorValue)));
+
+ // Application entities
+
+ EntitySpec<TestEntity> childSpec = EntitySpec.create(TestEntity.class)
+ .configure(BrooklynCampConstants.PLAN_ID, "child-plan")
+ .addInitializer(staticSensor);
+ EntitySpec<TestEntity> groupMemberSpec = EntitySpec.create(TestEntity.class)
+ .configure(BrooklynCampConstants.PLAN_ID, "group-member-plan")
+ .child(childSpec);
+ Entity cluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+ .configure(DynamicCluster.MEMBER_SPEC, groupMemberSpec)
+ .configure(Cluster.INITIAL_SIZE, 3));
+
+ // Start the cluster.
+ app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+ LoopOverGroupMembersTestCase groupTest = app.createAndManageChild(EntitySpec.create(LoopOverGroupMembersTestCase.class)
+ .configure(LoopOverGroupMembersTestCase.TARGET_ENTITY, cluster)
+ .configure(LoopOverGroupMembersTestCase.TEST_SPEC, relativeEntityTestCaseEntitySpec(
+ /* set by group-loop */ null, "child-plan", DslComponent.Scope.CHILD, sensorValue)));
+
+ groupTest.start(app.getLocations());
+
+ // Specifically check the result of the loop test.
+ assertTrue(groupTest.sensors().get(Attributes.SERVICE_UP), "Test case did not pass: " + groupTest);
+ }
+
+ private EntitySpec<RelativeEntityTestCase> relativeEntityTestCaseEntitySpec(
+ Entity testRoot, String targetEntityPlanId, DslComponent.Scope scope, String expectedSensorValue) {
+ EntitySpec<TestSensor> sensorTest = sensorHasValueTest(TestEntity.NAME, expectedSensorValue);
+
+ return EntitySpec.create(RelativeEntityTestCase.class)
+ .configure(RelativeEntityTestCase.TARGET_ENTITY, testRoot)
+ .configure(RelativeEntityTestCase.COMPONENT, new DslComponent(scope, targetEntityPlanId))
+ .child(sensorTest);
+ }
+
+ private EntitySpec<TestSensor> sensorHasValueTest(Sensor<?> sensorName, Object expectedValue) {
+ return EntitySpec.create(TestSensor.class)
+ .configure(TestSensor.SENSOR_NAME, sensorName.getName())
+ .configure(TestSensor.ASSERTIONS, ImmutableMap.of(
+ TestFrameworkAssertions.EQUAL_TO, expectedValue));
+ }
+
+}