Adds TargetableTestComponent.targetResolutionTimeout If no entity with the given id yet exists, then wait for this timeout for it to exist (defaults to zero, in which case fail immediately like it did before)
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/de12a4e8 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/de12a4e8 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/de12a4e8 Branch: refs/heads/master Commit: de12a4e8a77f7d2bfe1027ed08d6e1e0efb2ce39 Parents: ce1192f Author: Aled Sage <[email protected]> Authored: Thu Jun 30 13:16:57 2016 +0100 Committer: Aled Sage <[email protected]> Committed: Mon Jul 4 12:27:53 2016 +0100 ---------------------------------------------------------------------- .../test/framework/TargetableTestComponent.java | 11 +++ .../framework/TargetableTestComponentImpl.java | 47 +++++++--- .../framework/TargetableTestComponentTest.java | 96 ++++++++++++++++++++ 3 files changed, 140 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/de12a4e8/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java ---------------------------------------------------------------------- diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java index 8ae44ad..67daff6 100644 --- a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java +++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java @@ -20,9 +20,11 @@ package org.apache.brooklyn.test.framework; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.ImplementedBy; +import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.ConfigKeys; import org.apache.brooklyn.core.entity.trait.Startable; import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey; +import org.apache.brooklyn.util.time.Duration; /** * Entity that can target another entity for the purpouse of testing @@ -43,6 +45,15 @@ public interface TargetableTestComponent extends Entity, Startable { AttributeSensorAndConfigKey<String, String> TARGET_ID = ConfigKeys.newStringSensorAndConfigKey("targetId", "Id of the entity under test"); /** + * The duration to wait for an entity with the given targetId to exist, before throwing an exception. + */ + ConfigKey<Duration> TARGET_RESOLUTION_TIMEOUT = ConfigKeys.newConfigKey( + Duration.class, + "targetResolutionTimeout", + "Time to wait for targetId to exist (defaults to zero, i.e. must exist immediately)", + Duration.ZERO); + + /** * Get the target of the test. * * @return The target. http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/de12a4e8/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java ---------------------------------------------------------------------- diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java index 5b133bd..326e3ea 100644 --- a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java +++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java @@ -18,10 +18,8 @@ */ package org.apache.brooklyn.test.framework; -import java.util.concurrent.ExecutionException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicReference; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.mgmt.ExecutionContext; @@ -30,6 +28,10 @@ import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent; import org.apache.brooklyn.core.entity.AbstractEntity; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.repeat.Repeater; +import org.apache.brooklyn.util.time.Duration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Class that can resolve the target for a test component @@ -62,22 +64,39 @@ public abstract class TargetableTestComponentImpl extends AbstractEntity impleme return target; } - private static Entity getTargetById(ExecutionContext executionContext, Entity entity) { - String targetId = entity.getConfig(TARGET_ID); - + private static Entity getTargetById(final ExecutionContext executionContext, final Entity entity) { + final String targetId = entity.getConfig(TARGET_ID); + Duration resolutionTimeout = entity.getConfig(TARGET_RESOLUTION_TIMEOUT); + if(targetId == null){ return null; } - final Task<Entity> targetLookup = new DslComponent(targetId).newTask(); - Entity target = null; + final AtomicReference<Entity> result = new AtomicReference<>(); + final DslComponent dslComponent = new DslComponent(targetId); + Callable<Boolean> resolver = new Callable<Boolean>() { + @Override public Boolean call() throws Exception { + Task<Entity> task = dslComponent.newTask(); + result.set(Tasks.resolveValue(task, Entity.class, executionContext, "Finding entity " + targetId)); + return true; + } + }; try { - target = Tasks.resolveValue(targetLookup, Entity.class, executionContext, "Finding entity " + targetId); - LOG.debug("Found target by id {}", targetId); - } catch (final ExecutionException | InterruptedException e) { + if (resolutionTimeout == null || resolutionTimeout.toMilliseconds() <= 0) { + resolver.call(); + } else { + Repeater.create("find entity "+targetId) + .backoffTo(resolutionTimeout.multiply(0.1)) + .limitTimeTo(resolutionTimeout) + .rethrowException() + .until(resolver) + .runRequiringTrue(); + } + LOG.debug("Found target {} by id {}", result.get(), targetId); + return result.get(); + } catch (Exception e) { LOG.error("Error finding target {}", targetId); - Exceptions.propagate(e); + throw Exceptions.propagate(e); } - return target; } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/de12a4e8/test-framework/src/test/java/org/apache/brooklyn/test/framework/TargetableTestComponentTest.java ---------------------------------------------------------------------- diff --git a/test-framework/src/test/java/org/apache/brooklyn/test/framework/TargetableTestComponentTest.java b/test-framework/src/test/java/org/apache/brooklyn/test/framework/TargetableTestComponentTest.java new file mode 100644 index 0000000..dec0be7 --- /dev/null +++ b/test-framework/src/test/java/org/apache/brooklyn/test/framework/TargetableTestComponentTest.java @@ -0,0 +1,96 @@ +/* + * 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.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.api.sensor.AttributeSensor; +import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants; +import org.apache.brooklyn.core.sensor.Sensors; +import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; +import org.apache.brooklyn.core.test.entity.TestEntity; +import org.apache.brooklyn.util.time.Duration; +import org.apache.brooklyn.util.time.Time; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +public class TargetableTestComponentTest extends BrooklynAppUnitTestSupport { + + private static final AttributeSensor<String> STRING_SENSOR = Sensors.newStringSensor("string-sensor"); + + @Test + public void testTargetEntity() { + app.sensors().set(STRING_SENSOR, "myval"); + + app.addChild(EntitySpec.create(TestSensor.class) + .configure(TestSensor.TARGET_ENTITY, app) + .configure(TestSensor.SENSOR_NAME, STRING_SENSOR.getName()) + .configure(TestSensor.ASSERTIONS, ImmutableList.of(ImmutableMap.of("equals", "myval")))); + + app.start(ImmutableList.<Location>of()); + } + + @Test + public void testTargetEntityById() { + TestEntity target = app.addChild(EntitySpec.create(TestEntity.class) + .configure(BrooklynCampConstants.PLAN_ID, "myTargetId")); + target.sensors().set(STRING_SENSOR, "myval"); + + app.addChild(EntitySpec.create(TestSensor.class) + .configure(TestSensor.TARGET_ID, "myTargetId") + .configure(TestSensor.SENSOR_NAME, STRING_SENSOR.getName()) + .configure(TestSensor.ASSERTIONS, ImmutableList.of(ImmutableMap.of("equals", "myval")))); + + app.start(ImmutableList.<Location>of()); + } + + @Test + public void testTargetEntityByIdWithDelayedEntityCreation() { + final Duration entityCreationDelay = Duration.millis(250); + final Duration overheadDuration = Duration.seconds(10); + ExecutorService executor = Executors.newCachedThreadPool(); + + try { + executor.submit(new Runnable() { + @Override public void run() { + Time.sleep(entityCreationDelay); + TestEntity target = app.addChild(EntitySpec.create(TestEntity.class) + .configure(BrooklynCampConstants.PLAN_ID, "myTargetId")); + target.sensors().set(STRING_SENSOR, "myval"); + }}); + + app.addChild(EntitySpec.create(TestSensor.class) + .configure(TestSensor.TARGET_ID, "myTargetId") + .configure(TestSensor.TARGET_RESOLUTION_TIMEOUT, Duration.of(entityCreationDelay).add(overheadDuration)) + .configure(TestSensor.SENSOR_NAME, STRING_SENSOR.getName()) + .configure(TestSensor.ASSERTIONS, ImmutableList.of(ImmutableMap.of("equals", "myval")))); + + + app.start(ImmutableList.<Location>of()); + + } finally { + executor.shutdownNow(); + } + } +}
