| /* |
| * Copyright 2016 The Apache Software Foundation. |
| * |
| * Licensed 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.spi.dsl; |
| |
| import static org.testng.Assert.assertEquals; |
| |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.Future; |
| import java.util.concurrent.TimeUnit; |
| |
| import org.apache.brooklyn.api.entity.Entity; |
| import org.apache.brooklyn.api.location.Location; |
| import org.apache.brooklyn.api.sensor.AttributeSensor; |
| import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest; |
| import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslTestObjects.DslTestCallable; |
| import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslTestObjects.DslTestSupplierWrapper; |
| import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslTestObjects.TestDslSupplier; |
| import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslTestObjects.TestDslSupplierValue; |
| import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.custom.UserSuppliedPackageType; |
| import org.apache.brooklyn.config.ConfigKey; |
| import org.apache.brooklyn.core.config.ConfigKeys; |
| import org.apache.brooklyn.core.entity.EntityInternal; |
| import org.apache.brooklyn.core.sensor.Sensors; |
| import org.apache.brooklyn.core.test.entity.TestApplication; |
| import org.apache.brooklyn.core.test.entity.TestEntity; |
| import org.apache.brooklyn.entity.group.DynamicCluster; |
| import org.apache.brooklyn.entity.stock.BasicApplication; |
| import org.apache.brooklyn.entity.stock.BasicEntity; |
| import org.apache.brooklyn.entity.stock.BasicStartable; |
| import org.apache.brooklyn.test.Asserts; |
| import org.apache.brooklyn.util.collections.MutableMap; |
| import org.apache.brooklyn.util.guava.Maybe; |
| import org.testng.annotations.Test; |
| |
| import com.google.common.base.Function; |
| import com.google.common.collect.Iterables; |
| |
| // Doesn't test executing the DSL from different contexts (i.e. fetching the config from children inheriting it) |
| public class DslYamlTest extends AbstractYamlTest { |
| private static final ConfigKey<Object> DEST = ConfigKeys.newConfigKey(Object.class, "dest"); |
| private static final ConfigKey<Object> DEST2 = ConfigKeys.newConfigKey(Object.class, "dest2"); |
| private static final ConfigKey<Object> DEST3 = ConfigKeys.newConfigKey(Object.class, "dest3"); |
| |
| // See also test-referencing-entities.yaml |
| |
| // No tests for entitySpec, object, formatString, external - relying on extensive tests elsewhere |
| |
| @Test |
| public void testDslSelf() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:self()"); |
| assertEquals(getConfigEventually(app, DEST), app); |
| } |
| |
| @Test |
| public void testDslEntity() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:entity(\"child\")", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " id: child"); |
| assertEquals(getConfigEventually(app, DEST), Iterables.getOnlyElement(app.getChildren())); |
| } |
| |
| @Test |
| public void testDslParent() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:parent()"); |
| final Entity child = Iterables.getOnlyElement(app.getChildren()); |
| assertEquals(getConfigEventually(child, DEST), app); |
| } |
| |
| @Test |
| public void testDslChild() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:child(\"child\")", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " id: child", |
| " - type: " + BasicEntity.class.getName(), |
| " id: another-child"); |
| assertEquals(getConfigEventually(app, DEST), app.getChildren().iterator().next()); |
| } |
| |
| @Test |
| public void testDslSibling() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " id: child", |
| " brooklyn.config:", |
| " dest: $brooklyn:sibling(\"another-child\")", |
| " - type: " + BasicEntity.class.getName(), |
| " id: another-child"); |
| final Entity child1 = Iterables.get(app.getChildren(), 0); |
| final Entity child2 = Iterables.get(app.getChildren(), 1); |
| assertEquals(getConfigEventually(child1, DEST), child2); |
| } |
| |
| @Test |
| public void testDslDescendant() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " id: self", |
| " brooklyn.config:", |
| " dest: $brooklyn:descendant(\"child\")", |
| " dest2: $brooklyn:descendant(\"grand-child\")", |
| " dest3: $brooklyn:descendant(\"self\")", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " id: child", |
| " - type: " + BasicEntity.class.getName(), |
| " id: another-child", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " id: grand-child"); |
| final Entity child1 = Iterables.get(app.getChildren(), 0); |
| final Entity child2 = Iterables.get(app.getChildren(), 1); |
| final Entity grandChild = Iterables.getOnlyElement(child2.getChildren()); |
| assertEquals(getConfigEventually(app, DEST), child1); |
| assertEquals(getConfigEventually(app, DEST2), grandChild); |
| try { |
| assertEquals(getConfigEventually(app, DEST3), app); |
| Asserts.shouldHaveFailedPreviously("Self not in descendant scope"); |
| } catch (Exception e) { |
| Asserts.expectedFailureContains(e, "No entity matching id self"); |
| } |
| } |
| |
| @Test |
| public void testDslAncestor() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " id: app", |
| " brooklyn.config:", |
| " dest: $brooklyn:ancestor(\"app\")", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:ancestor(\"app\")", |
| " - type: " + BasicEntity.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:ancestor(\"app\")", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:ancestor(\"app\")"); |
| final Entity child1 = Iterables.get(app.getChildren(), 0); |
| final Entity child2 = Iterables.get(app.getChildren(), 1); |
| final Entity grandChild = Iterables.getOnlyElement(child2.getChildren()); |
| assertEquals(getConfigEventually(child1, DEST), app); |
| assertEquals(getConfigEventually(child2, DEST), app); |
| assertEquals(getConfigEventually(grandChild, DEST), app); |
| try { |
| assertEquals(getConfigEventually(app, DEST), app); |
| Asserts.shouldHaveFailedPreviously("App not in ancestor scope"); |
| } catch (Exception e) { |
| Asserts.expectedFailureContains(e, "No entity matching id app"); |
| } |
| } |
| |
| @Test |
| public void testDslRoot() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " id: app", |
| " brooklyn.config:", |
| " dest: $brooklyn:root()", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:root()", |
| " - type: " + BasicEntity.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:root()", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:root()"); |
| final Entity child1 = Iterables.get(app.getChildren(), 0); |
| final Entity child2 = Iterables.get(app.getChildren(), 1); |
| final Entity grandChild = Iterables.getOnlyElement(child2.getChildren()); |
| assertEquals(getConfigEventually(child1, DEST), app); |
| assertEquals(getConfigEventually(child2, DEST), app); |
| assertEquals(getConfigEventually(grandChild, DEST), app); |
| assertEquals(getConfigEventually(app, DEST), app); |
| } |
| |
| @Test |
| public void testDslScopeRoot() throws Exception { |
| addCatalogItems( |
| "brooklyn.catalog:", |
| " version: " + TEST_VERSION, |
| " items:", |
| " - id: simple-item", |
| " itemType: entity", |
| " item:", |
| " type: "+ BasicEntity.class.getName(), |
| " - id: wrapping-plain", |
| " itemType: entity", |
| " item:", |
| " type: "+ BasicEntity.class.getName(), |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:scopeRoot()", |
| " - id: wrapping-simple", |
| " itemType: entity", |
| " item:", |
| " type: "+ BasicEntity.class.getName(), |
| " brooklyn.children:", |
| " - type: simple-item", |
| " brooklyn.config:", |
| " dest: $brooklyn:scopeRoot()"); |
| |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.children:", |
| " - type: wrapping-plain", |
| " - type: wrapping-simple"); |
| Entity child1 = Iterables.get(app.getChildren(), 0); |
| Entity child2 = Iterables.get(app.getChildren(), 1); |
| assertScopeRoot(child1, false); |
| // TODO Not the result I'd expect - in both cases the entity argument should the the scopeRoot element, not its child |
| assertScopeRoot(child2, true); |
| } |
| |
| private void assertScopeRoot(Entity entity, boolean isScopeBugged) throws Exception { |
| Entity child = Iterables.getOnlyElement(entity.getChildren()); |
| if (!isScopeBugged) { |
| assertEquals(getConfigEventually(child, DEST), entity); |
| } else { |
| assertEquals(getConfigEventually(child, DEST), child); |
| } |
| } |
| |
| @Test |
| public void testDslConfig() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " source: myvalue", |
| " dest: $brooklyn:config(\"source\")"); |
| assertEquals(getConfigEventually(app, DEST), "myvalue"); |
| } |
| |
| @Test |
| public void testDslConfigInMap() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " source: myvalue", |
| " dest:", |
| " key: $brooklyn:config(\"source\")"); |
| assertEquals(getConfigEventually(app, DEST), MutableMap.of("key", "myvalue")); |
| } |
| |
| @Test |
| public void testDslConfigOnEntity() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:entity(\"sourceEntity\").config(\"source\")", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " id: sourceEntity", |
| " brooklyn.config:", |
| " source: myvalue"); |
| assertEquals(getConfigEventually(app, DEST), "myvalue"); |
| } |
| |
| @Test |
| public void testDslConfigWithDeferredArg() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " source: myvalue", |
| " configName: source", |
| " dest: $brooklyn:config(config(\"configName\"))"); |
| assertEquals(getConfigEventually(app, DEST), "myvalue"); |
| } |
| |
| @Test |
| public void testDslConfigOnEntityWithDeferredArgAsEntityId() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " entityName: sourceEntity", |
| " configName: source", |
| " dest: $brooklyn:entity(config(\"entityName\")).config(config(\"configName\"))", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " id: sourceEntity", |
| " brooklyn.config:", |
| " source: myvalue"); |
| assertEquals(getConfigEventually(app, DEST), "myvalue"); |
| } |
| |
| @Test |
| public void testDslConfigOnEntityWithDeferredArgAsEntity() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " entityValue: $brooklyn:entity(\"sourceEntity\")", |
| " configName: source", |
| " dest: $brooklyn:entity(config(\"entityValue\")).config(config(\"configName\"))", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " id: sourceEntity", |
| " brooklyn.config:", |
| " source: myvalue"); |
| assertEquals(getConfigEventually(app, DEST), "myvalue"); |
| } |
| |
| @Test |
| public void testDslAttributeWhenReady() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.initializers:", |
| " - type: org.apache.brooklyn.core.sensor.StaticSensor", |
| " brooklyn.config:", |
| " name: source", |
| " static.value: myvalue", |
| " brooklyn.config:", |
| " dest: $brooklyn:attributeWhenReady(\"source\")"); |
| assertEquals(getConfigEventually(app, DEST), "myvalue"); |
| } |
| |
| @Test |
| public void testDslAttributeWhenReadyOnEntity() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:entity(\"sourceEntity\").attributeWhenReady(\"source\")", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " id: sourceEntity", |
| " brooklyn.initializers:", |
| " - type: org.apache.brooklyn.core.sensor.StaticSensor", |
| " brooklyn.config:", |
| " name: source", |
| " static.value: myvalue"); |
| assertEquals(getConfigEventually(app, DEST), "myvalue"); |
| } |
| |
| @Test |
| public void testDslAttributeWhenReadyWithDeferredArg() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.initializers:", |
| " - type: org.apache.brooklyn.core.sensor.StaticSensor", |
| " brooklyn.config:", |
| " name: source", |
| " static.value: myvalue", |
| " brooklyn.config:", |
| " configName: source", |
| " dest: $brooklyn:attributeWhenReady(config(\"configName\"))"); |
| assertEquals(getConfigEventually(app, DEST), "myvalue"); |
| } |
| |
| @Test |
| public void testDslAttributeWhenReadyOnEntityWithDeferredArg() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " entityName: sourceEntity", |
| " configName: source", |
| " dest: $brooklyn:entity(config(\"entityName\")).attributeWhenReady(config(\"configName\"))", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " id: sourceEntity", |
| " brooklyn.initializers:", |
| " - type: org.apache.brooklyn.core.sensor.StaticSensor", |
| " brooklyn.config:", |
| " name: source", |
| " static.value: myvalue"); |
| assertEquals(getConfigEventually(app, DEST), "myvalue"); |
| } |
| |
| @Test |
| public void testDslEntityId() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:entityId()"); |
| assertEquals(getConfigEventually(app, DEST), app.getId()); |
| } |
| |
| @Test |
| public void testDslEntityIdOnEntity() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:entity(\"sourceEntity\").entityId()", |
| " brooklyn.children:", |
| " - type: " + BasicEntity.class.getName(), |
| " id: sourceEntity"); |
| final Entity child = Iterables.getOnlyElement(app.getChildren()); |
| assertEquals(getConfigEventually(app, DEST), child.getId()); |
| } |
| |
| @Test |
| public void testDslSensor() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + TestApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:sensor(\"test.myattribute\")"); |
| assertEquals(getConfigEventually(app, DEST), TestApplication.MY_ATTRIBUTE); |
| } |
| |
| @Test |
| public void testDslSensorOnEntity() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:entity(\"sourceEntity\").sensor(\"test.myattribute\")", |
| " brooklyn.children:", |
| " - type: " + TestApplication.class.getName(), |
| " id: sourceEntity"); |
| assertEquals(getConfigEventually(app, DEST), TestApplication.MY_ATTRIBUTE); |
| } |
| |
| @Test |
| public void testDslSensorWithClass() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:sensor(\"org.apache.brooklyn.core.test.entity.TestApplication\", \"test.myattribute\")"); |
| assertEquals(getConfigEventually(app, DEST), TestApplication.MY_ATTRIBUTE); |
| } |
| |
| @Test |
| public void testDslLiteral() throws Exception { |
| final String literal = "custom(), $brooklyn:root(), invalid; syntax"; |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + TestApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:literal(\"" + literal + "\")"); |
| assertEquals(getConfigEventually(app, DEST), literal); |
| } |
| |
| @Test |
| public void testDslRegexReplacement() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + TestApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:regexReplacement(\"Broooklyn\", \"o+\", \"oo\")"); |
| assertEquals(getConfigEventually(app, DEST), "Brooklyn"); |
| } |
| |
| @Test |
| public void testDslRegexReplacementWithDeferredArg() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + TestApplication.class.getName(), |
| " brooklyn.config:", |
| " source: Broooklyn", |
| " pattern: o+", |
| " replacement: oo", |
| " dest: $brooklyn:regexReplacement(config(\"source\"), config(\"pattern\"), config(\"replacement\"))"); |
| assertEquals(getConfigEventually(app, DEST), "Brooklyn"); |
| } |
| |
| @Test |
| public void testDslFunctionRegexReplacement() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + TestApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:function.regexReplacement(\"o+\", \"oo\")"); |
| @SuppressWarnings("unchecked") |
| Function<String, String> replacementFn = (Function<String, String>) getConfigEventually(app, DEST); |
| assertEquals(replacementFn.apply("Broooklyn"), "Brooklyn"); |
| } |
| |
| @Test |
| public void testDslFunctionRegexReplacementWithDeferredArg() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + TestApplication.class.getName(), |
| " brooklyn.config:", |
| " source: Broooklyn", |
| " pattern: o+", |
| " replacement: oo", |
| " dest: $brooklyn:function.regexReplacement(config(\"pattern\"), config(\"replacement\"))"); |
| @SuppressWarnings("unchecked") |
| Function<String, String> replacementFn = (Function<String, String>) getConfigEventually(app, DEST); |
| assertEquals(replacementFn.apply("Broooklyn"), "Brooklyn"); |
| } |
| |
| @Test |
| public void testDslNonDeferredInvalidMethod() throws Exception { |
| try { |
| createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:self().invalidMethod()"); |
| Asserts.shouldHaveFailedPreviously("Non-existing non-deferred method should fail deployment"); |
| } catch (Exception e) { |
| Asserts.expectedFailureContains(e, "No such function 'invalidMethod'"); |
| } |
| } |
| |
| public static class InaccessibleType { |
| public static boolean doesFail() {return true;} |
| @DslAccessible |
| public static boolean doesSucceed() {return true;} |
| } |
| |
| @Test |
| public void testDeferredDslInaccessibleCall() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"targetValue\").doesFail()"); |
| app.config().set(ConfigKeys.newConfigKey(InaccessibleType.class, "targetValue"), new InaccessibleType()); |
| try { |
| getConfigEventually(app, DEST); |
| Asserts.shouldHaveFailedPreviously("Outside of allowed package scope"); |
| } catch (ExecutionException e) { |
| Asserts.expectedFailureContains(e, "(outside allowed package scope)"); |
| } |
| } |
| |
| @Test |
| public void testDeferredDslAccessible() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"targetValue\").doesSucceed()"); |
| app.config().set(ConfigKeys.newConfigKey(InaccessibleType.class, "targetValue"), new InaccessibleType()); |
| assertEquals(getConfigEventually(app, DEST), Boolean.TRUE); |
| } |
| |
| @Test |
| public void testDeferredDslWhiteListPackage() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"targetValue\").isSupplierEvaluated()"); |
| app.config().set(ConfigKeys.newConfigKey(TestDslSupplierValue.class, "targetValue"), new TestDslSupplierValue()); |
| assertEquals(getConfigEventually(app, DEST), Boolean.TRUE); |
| } |
| |
| @Test |
| public void testDeferredDslUserSuppliedPackage() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"targetValue\").isEvaluated()"); |
| app.config().set(ConfigKeys.newConfigKey(UserSuppliedPackageType.class, "targetValue"), new UserSuppliedPackageType()); |
| assertEquals(getConfigEventually(app, DEST), Boolean.TRUE); |
| } |
| |
| @Test |
| public void testDeferredDslChainingOnConfig() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"targetValue\").isSupplierEvaluated()"); |
| app.config().set(ConfigKeys.newConfigKey(TestDslSupplierValue.class, "targetValue"), new TestDslSupplierValue()); |
| assertEquals(getConfigEventually(app, DEST), Boolean.TRUE); |
| } |
| |
| @Test |
| public void testDeferredDslChainingDslComponent() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"targetValue\").self().attributeWhenReady(\"entity.id\")"); |
| app.config().set(ConfigKeys.newConfigKey(TestDslSupplierValue.class, "targetValue"), new TestDslSupplierValue()); |
| assertEquals(getConfigEventually(app, DEST), app.getId()); |
| } |
| |
| @Test |
| public void testDeferredDslChainingOnConfigNoFunction() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"targetValue\").getNonExistent()"); |
| ConfigKey<TestDslSupplierValue> targetValueKey = ConfigKeys.newConfigKey(TestDslSupplierValue.class, "targetValue"); |
| app.config().set(targetValueKey, new TestDslSupplierValue()); |
| try { |
| assertEquals(getConfigEventually(app, DEST), app.getId()); |
| Asserts.shouldHaveFailedPreviously("Expected to fail because method does not exist"); |
| } catch (Exception e) { |
| Asserts.expectedFailureContains(e, "No such function 'getNonExistent'"); |
| Asserts.expectedFailureDoesNotContain(e, "$brooklyn:$brooklyn:"); |
| } |
| } |
| |
| @Test |
| public void testDeferredDslChainingOnSensor() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:attributeWhenReady(\"targetValue\").isSupplierEvaluated()"); |
| AttributeSensor<TestDslSupplierValue> targetValueSensor = Sensors.newSensor(TestDslSupplierValue.class, "targetValue"); |
| app.sensors().set(targetValueSensor, new TestDslSupplierValue()); |
| assertEquals(getConfigEventually(app, DEST), Boolean.TRUE); |
| } |
| |
| @Test |
| public void testDeferredDslObjectAsFirstArgument() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " location: localhost", |
| " brooklyn.config:", |
| " dest: $brooklyn:attributeWhenReady(\"targetValue\").config(\"spec.final\")"); |
| AttributeSensor<Location> targetValueSensor = Sensors.newSensor(Location.class, "targetValue"); |
| app.sensors().set(targetValueSensor, Iterables.getOnlyElement(app.getLocations())); |
| assertEquals(getConfigEventually(app, DEST), "localhost"); |
| } |
| |
| |
| @Test |
| public void testDeferredDslAttributeFacade() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:attributeWhenReady(\"targetEntity\").attributeWhenReady(\"entity.id\")"); |
| AttributeSensor<Entity> targetEntitySensor = Sensors.newSensor(Entity.class, "targetEntity"); |
| app.sensors().set(targetEntitySensor, app); |
| assertEquals(getConfigEventually(app, DEST), app.getId()); |
| } |
| |
| @Test |
| public void testDeferredDslConfigFacade() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " testValue: myvalue", |
| " targetEntity: $brooklyn:self()", |
| " dest: $brooklyn:config(\"targetEntity\").config(\"testValue\")"); |
| AttributeSensor<Entity> targetEntitySensor = Sensors.newSensor(Entity.class, "targetEntity"); |
| app.sensors().set(targetEntitySensor, app); |
| assertEquals(getConfigEventually(app, DEST), "myvalue"); |
| } |
| |
| @Test |
| public void testDeferredDslConfigFacadeCrossAppFails() throws Exception { |
| final Entity app0 = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName()); |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"targetEntity\").attributeWhenReady(\"entity.id\")"); |
| app.config().set(ConfigKeys.newConfigKey(Entity.class, "targetEntity"), app0); |
| try { |
| getConfigEventually(app, DEST); |
| Asserts.shouldHaveFailedPreviously("Cross-app DSL not allowed"); |
| } catch (ExecutionException e) { |
| Asserts.expectedFailureContains(e, "not in scope 'global'"); |
| } |
| } |
| |
| @Test |
| public void testDeferredDslAttributeFacadeCrossAppFails() throws Exception { |
| final Entity app0 = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName()); |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:attributeWhenReady(\"targetEntity\").attributeWhenReady(\"entity.id\")"); |
| AttributeSensor<Entity> targetEntitySensor = Sensors.newSensor(Entity.class, "targetEntity"); |
| app.sensors().set(targetEntitySensor, app0); |
| try { |
| getConfigEventually(app, DEST); |
| Asserts.shouldHaveFailedPreviously("Cross-app DSL not allowed"); |
| } catch (ExecutionException e) { |
| Asserts.expectedFailureContains(e, "not in scope 'global'"); |
| } |
| } |
| |
| @Test |
| public void testDeferredDslChainingOnNullConfig() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"targetEntity\").getId()"); |
| try { |
| assertEquals(getConfigEventually(app, DEST), app.getId()); |
| Asserts.shouldHaveFailedPreviously("Expected to fail because targetEntity config is null"); |
| } catch (Exception e) { |
| Asserts.expectedFailureContains(e, "config(\"targetEntity\") evaluates to null"); |
| } |
| } |
| |
| @Test |
| public void testDeferredDslChainingWithCustomSupplier() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"customSupplierWrapper\").getSupplier().isSupplierEvaluated()"); |
| ConfigKey<DslTestSupplierWrapper> customSupplierWrapperKey = ConfigKeys.newConfigKey(DslTestSupplierWrapper.class, "customSupplierWrapper"); |
| app.config().set(customSupplierWrapperKey, new DslTestSupplierWrapper(new TestDslSupplier(new TestDslSupplierValue()))); |
| assertEquals(getConfigEventually(app, DEST), Boolean.TRUE); |
| } |
| |
| @Test |
| public void testDeferredDslChainingWithCustomCallable() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"customCallableWrapper\").getSupplier().isSupplierCallable()"); |
| ConfigKey<DslTestSupplierWrapper> customCallableWrapperKey = ConfigKeys.newConfigKey(DslTestSupplierWrapper.class, "customCallableWrapper"); |
| app.config().set(customCallableWrapperKey, new DslTestSupplierWrapper(new DslTestCallable())); |
| assertEquals(getConfigEventually(app, DEST), Boolean.TRUE); |
| } |
| |
| @Test |
| public void testDeferredDslChainingWithNestedEvaluation() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"customCallableWrapper\").getSupplier().isSupplierCallable()"); |
| ConfigKey<TestDslSupplier> customCallableWrapperKey = ConfigKeys.newConfigKey(TestDslSupplier.class, "customCallableWrapper"); |
| app.config().set(customCallableWrapperKey, new TestDslSupplier(new DslTestSupplierWrapper(new DslTestCallable()))); |
| assertEquals(getConfigEventually(app, DEST), Boolean.TRUE); |
| } |
| |
| @Test |
| public void testDslTemplate() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " test.sourceName: hello world", |
| " dest: $brooklyn:template(\"${config['test.sourceName']}\")"); |
| assertEquals(getConfigEventually(app, DEST), "hello world"); |
| } |
| |
| @Test |
| public void testDslTemplateSubstitutions() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " test.sourceName: hello world", |
| " test.substituteValue: and all", |
| " dest: ", |
| " $brooklyn:template:", |
| " - ${config['test.sourceName']} ${key}", |
| " - $brooklyn:literal(\"key\"): $brooklyn:config(\"test.substituteValue\")"); |
| assertEquals(getConfigEventually(app, DEST), "hello world and all"); |
| } |
| |
| @Test |
| public void testDslTemplateOnEntity() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:entity(\"configSource\").template(\"${config['test.sourceName']}\")", |
| "- type: " + BasicApplication.class.getName(), |
| " id: configSource", |
| " brooklyn.config:", |
| " test.sourceName: hello world"); |
| assertEquals(getConfigEventually(app.getChildren().iterator().next(), DEST), "hello world"); |
| } |
| |
| @Test |
| public void testDslMultilineTemplate() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " test.sourceName: hello world", |
| " dest: ", |
| " $brooklyn:template:", |
| " - |", |
| " ${config['test.sourceName']}"); |
| assertEquals(getConfigEventually(app, DEST), "hello world"); |
| } |
| |
| @Test |
| public void testDslTemplateOverDsl() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " test.value: hello world", |
| " test.sourceDsl: $brooklyn:config(\"test.value\")", |
| " test.sourceTemplate: ${config['test.sourceDsl']}", |
| " dest: $brooklyn:template($brooklyn:config(\"test.sourceTemplate\"))"); |
| assertEquals(getConfigEventually(app, DEST), "hello world"); |
| } |
| |
| @Test |
| public void testDslRecursiveFails() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " dest: $brooklyn:config(\"dest\")"); |
| try { |
| getConfigEventually(app, DEST); |
| Asserts.shouldHaveFailedPreviously(); |
| } catch (Exception e) { |
| Asserts.expectedFailureContains(e, "Recursive reference DSL:entity('", "').config('dest')"); |
| } |
| } |
| |
| @Test |
| public void testDslRecursiveFails2() throws Exception { |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " val: $brooklyn:config(\"dest\")", |
| " dest: $brooklyn:config(\"val\")"); |
| try { |
| getConfigEventually(app, DEST); |
| Asserts.shouldHaveFailedPreviously(); |
| } catch (Exception e) { |
| Asserts.expectedFailureContains(e, "Recursive reference DSL:entity('", "').config('val')"); |
| } |
| } |
| |
| @Test |
| public void testDslFromParentConfigNotRecursive() throws Exception { |
| // Broke this in https://github.com/apache/brooklyn-server/pull/971. |
| // It thought that the '$brooklyn:parent().config("test.value")' was the |
| // same each time, rather than 'parent' resolving differently each time. |
| |
| final Entity app = createAndStartApplication( |
| "services:", |
| "- type: " + BasicApplication.class.getName(), |
| " brooklyn.config:", |
| " test.value: 0", |
| " brooklyn.children:", |
| " - type: "+BasicStartable.class.getName(), |
| " brooklyn.config:", |
| " test.value: $brooklyn:parent().config(\"test.value\")", |
| " brooklyn.children:", |
| " - type: "+DynamicCluster.class.getName(), |
| " brooklyn.config:", |
| " cluster.initial.size: $brooklyn:parent().config(\"test.value\")", |
| " memberSpec:", |
| " $brooklyn:entitySpec:", |
| " type: "+TestEntity.class.getName()); |
| |
| BasicStartable child = (BasicStartable) Iterables.getOnlyElement(app.getChildren()); |
| DynamicCluster cluster = (DynamicCluster) Iterables.getOnlyElement(child.getChildren()); |
| assertEquals(cluster.config().get(DynamicCluster.INITIAL_SIZE), Integer.valueOf(0)); |
| } |
| |
| private static <T> T getConfigEventually(final Entity entity, final ConfigKey<T> configKey) throws Exception { |
| // Use an executor, in case config().get() blocks forever, waiting for the config value. |
| ExecutorService executor = Executors.newSingleThreadExecutor(); |
| try { |
| Future<T> future = executor.submit(new Callable<T>() { |
| public T call() { |
| T blockingValue = entity.config().get(configKey); |
| Maybe<T> immediateValue = ((EntityInternal)entity).config().getNonBlocking(configKey); |
| assertEquals(immediateValue.get(), blockingValue); |
| return blockingValue; |
| }}); |
| return future.get(Asserts.DEFAULT_LONG_TIMEOUT.toMilliseconds(), TimeUnit.MILLISECONDS); |
| } finally { |
| executor.shutdownNow(); |
| } |
| } |
| } |