/*
* 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.catalog;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import java.util.Iterator;
import java.util.List;
import org.apache.brooklyn.api.catalog.CatalogItem;
import org.apache.brooklyn.api.entity.Application;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
import org.apache.brooklyn.api.objs.BrooklynObject;
import org.apache.brooklyn.api.objs.SpecParameter;
import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
import org.apache.brooklyn.core.entity.AbstractApplication;
import org.apache.brooklyn.core.entity.AbstractEntity;
import org.apache.brooklyn.core.location.AbstractLocation;
import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
import org.apache.brooklyn.core.objs.BasicSpecParameter;
import org.apache.brooklyn.core.policy.AbstractPolicy;
import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
import org.apache.brooklyn.entity.stock.BasicApplication;
import org.testng.SkipException;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
public class SpecParameterUnwrappingTest extends AbstractYamlTest {
private static final String SYMBOLIC_NAME = "my.catalog.app.id.load";
private static final ConfigKey<String> SHARED_CONFIG = ConfigKeys.newStringConfigKey("sample.config");
public static class ConfigAppForTest extends AbstractApplication {
public static final ConfigKey<String> SAMPLE_CONFIG = SHARED_CONFIG;
}
public static class ConfigEntityForTest extends AbstractEntity {
public static final ConfigKey<String> SAMPLE_CONFIG = SHARED_CONFIG;
}
public static class ConfigPolicyForTest extends AbstractPolicy {
public static final ConfigKey<String> SAMPLE_CONFIG = SHARED_CONFIG;
}
public static class ConfigLocationForTest extends AbstractLocation {
public static final ConfigKey<String> SAMPLE_CONFIG = SHARED_CONFIG;
}
@Override
protected LocalManagementContext newTestManagementContext() {
// Don't need OSGi
return LocalManagementContextForTests.newInstance();
}
@DataProvider(name="brooklynTypes")
public Object[][] brooklynTypes() {
return new Object[][] {
{ConfigEntityForTest.class},
{ConfigPolicyForTest.class},
{ConfigLocationForTest.class}};
}
@Test(dataProvider = "brooklynTypes")
public void testParameters(Class<? extends BrooklynObject> testClass) {
addCatalogItems("brooklyn.catalog:",
" id: " + SYMBOLIC_NAME,
" version: " + TEST_VERSION,
" item:",
" type: " + testClass.getName(),
" brooklyn.parameters:",
" - simple");
ConfigKey<String> SIMPLE_CONFIG = ConfigKeys.newStringConfigKey("simple");
SpecParameter<String> SIMPLE_PARAM = new BasicSpecParameter<>("simple", true, SIMPLE_CONFIG);
CatalogItem<?, ?> item = catalog.getCatalogItem(SYMBOLIC_NAME, TEST_VERSION);
AbstractBrooklynObjectSpec<?,?> spec = createSpec(item);
assertEquals(ImmutableSet.copyOf(spec.getParameters()), ImmutableList.of(SIMPLE_PARAM));
}
@Test(dataProvider = "brooklynTypes")
public void testDefaultParameters(Class<? extends BrooklynObject> testClass) {
addCatalogItems(
"brooklyn.catalog:",
" id: " + SYMBOLIC_NAME,
" version: " + TEST_VERSION,
" item:",
" type: "+ testClass.getName());
CatalogItem<?, ?> item = catalog.getCatalogItem(SYMBOLIC_NAME, TEST_VERSION);
AbstractBrooklynObjectSpec<?, ?> spec = createSpec(item);
assertEquals(ImmutableSet.copyOf(spec.getParameters()), ImmutableSet.copyOf(BasicSpecParameter.fromClass(mgmt(),testClass)));
}
@Test
public void testRootParametersUnwrapped() {
addCatalogItems(
"brooklyn.catalog:",
" id: " + SYMBOLIC_NAME,
" version: " + TEST_VERSION,
" item:",
" services:",
" - type: " + ConfigEntityForTest.class.getName(),
" brooklyn.parameters:",
" - simple");
CatalogItem<?, ?> item = catalog.getCatalogItem(SYMBOLIC_NAME, TEST_VERSION);
AbstractBrooklynObjectSpec<?,?> spec = createSpec(item);
List<SpecParameter<?>> inputs = spec.getParameters();
assertEquals(inputs.size(), 1);
SpecParameter<?> firstInput = inputs.get(0);
assertEquals(firstInput.getLabel(), "simple");
}
@Test(dataProvider="brooklynTypes")
public void testDepentantCatalogsInheritParameters(Class<? extends BrooklynObject> type) {
if (type == ConfigLocationForTest.class) {
//TODO
throw new SkipException("Locations don't inherit parameters, should migrate to the type registry first");
}
addCatalogItems(
"brooklyn.catalog:",
" version: " + TEST_VERSION,
" items:",
" - id: paramItem",
" item:",
" type: " + type.getName(),
" brooklyn.parameters:",
" - simple",
" - id: " + SYMBOLIC_NAME,
" item:",
" type: paramItem:" + TEST_VERSION);
CatalogItem<?, ?> item = catalog.getCatalogItem(SYMBOLIC_NAME, TEST_VERSION);
AbstractBrooklynObjectSpec<?,?> spec = createSpec(item);
List<SpecParameter<?>> inputs = spec.getParameters();
assertEquals(inputs.size(), 1);
SpecParameter<?> firstInput = inputs.get(0);
assertEquals(firstInput.getLabel(), "simple");
}
@Test(dataProvider="brooklynTypes")
public void testDepentantCatalogsOverrideParameters(Class<? extends BrooklynObject> type) {
addCatalogItems(
"brooklyn.catalog:",
" version: " + TEST_VERSION,
" items:",
" - id: paramItem",
" item:",
" type: " + type.getName(),
" brooklyn.parameters:",
" - simple",
" - id: " + SYMBOLIC_NAME,
" item:",
// Don't set explicit version, not supported by locations
" type: paramItem",
" brooklyn.parameters:",
" - override");
CatalogItem<?, ?> item = catalog.getCatalogItem(SYMBOLIC_NAME, TEST_VERSION);
AbstractBrooklynObjectSpec<?,?> spec = createSpec(item);
List<SpecParameter<?>> inputs = spec.getParameters();
assertEquals(inputs.size(), 1);
SpecParameter<?> firstInput = inputs.get(0);
assertEquals(firstInput.getLabel(), "override");
}
@Test
public void testChildEntitiyHasParameters() {
addCatalogItems(
"brooklyn.catalog:",
" id: " + SYMBOLIC_NAME,
" version: " + TEST_VERSION,
" items:",
" - item:",
" type: " + ConfigEntityForTest.class.getName(),
" brooklyn.children:",
" - type: " + ConfigEntityForTest.class.getName(),
" brooklyn.parameters:",
" - simple");
CatalogItem<?, ?> item = catalog.getCatalogItem(SYMBOLIC_NAME, TEST_VERSION);
@SuppressWarnings({ "rawtypes", "unchecked"})
EntitySpec<?> parentSpec = (EntitySpec<?>) catalog.createSpec((CatalogItem)item);
EntitySpec<?> spec = parentSpec.getChildren().get(0);
SpecParameter<?> firstInput = spec.getParameters().get(0);
assertEquals(firstInput.getLabel(), "simple");
}
@Test
public void testAppSpecInheritsCatalogParameters() {
addCatalogItems(
"brooklyn.catalog:",
" version: " + TEST_VERSION,
" items:",
" - id: " + SYMBOLIC_NAME,
" item:",
" type: " + BasicApplication.class.getName(),
" brooklyn.parameters:",
" - simple");
EntitySpec<? extends Application> spec = createAppSpec(
"services:",
"- type: " + ver(SYMBOLIC_NAME));
List<SpecParameter<?>> params = spec.getParameters();
assertEquals(params.size(), 1);
SpecParameter<?> firstInput = params.get(0);
assertEquals(firstInput.getLabel(), "simple");
}
@Test
public void testAppSpecInheritsCatalogRootParameters() {
addCatalogItems(
"brooklyn.catalog:",
" version: " + TEST_VERSION,
" items:",
" - id: " + SYMBOLIC_NAME,
" item:",
" type: " + BasicApplication.class.getName(),
" brooklyn.parameters:",
" - simple");
EntitySpec<? extends Application> spec = createAppSpec(
"services:",
"- type: " + ver(SYMBOLIC_NAME));
List<SpecParameter<?>> params = spec.getParameters();
assertEquals(params.size(), 1);
SpecParameter<?> firstInput = params.get(0);
assertEquals(firstInput.getLabel(), "simple");
}
@Test
public void testAppSpecInheritsCatalogRootParametersWithServices() {
addCatalogItems(
"brooklyn.catalog:",
" version: " + TEST_VERSION,
" items:",
" - id: " + SYMBOLIC_NAME,
" item:",
" brooklyn.parameters:",
" - simple",
" services:",
" - type: " + BasicApplication.class.getName());
EntitySpec<? extends Application> spec = createAppSpec(
"services:",
"- type: " + ver(SYMBOLIC_NAME));
List<SpecParameter<?>> params = spec.getParameters();
assertEquals(params.size(), 1);
SpecParameter<?> firstInput = params.get(0);
assertEquals(firstInput.getLabel(), "simple");
}
@Test
public void testUnresolvedCatalogItemParameters() {
// Insert template which is not instantiatable during catalog addition due to
// missing dependencies, but the spec can be created (the
// dependencies are already parsed).
addCatalogItems(
"brooklyn.catalog:",
" version: " + TEST_VERSION,
" items:",
" - id: " + SYMBOLIC_NAME,
" itemType: template",
" item:",
" services:",
" - type: basic-app",
" - id: basic-app",
" item:",
" type: " + ConfigAppForTest.class.getName());
EntitySpec<? extends Application> spec = createAppSpec(
"services:",
"- type: " + ver(SYMBOLIC_NAME));
List<SpecParameter<?>> params = spec.getParameters();
assertEquals(params.size(), 2); // sample + defaultDisplayName
assertEquals(ImmutableSet.copyOf(params), ImmutableSet.copyOf(BasicSpecParameter.fromClass(mgmt(), ConfigAppForTest.class)));
}
@Test
public void testParametersCoercedOnSetAndReferences() throws Exception {
Integer testValue = Integer.valueOf(55);
addCatalogItems(
"brooklyn.catalog:",
" id: " + SYMBOLIC_NAME,
" version: " + TEST_VERSION,
" item:",
" type: " + BasicApplication.class.getName(),
" brooklyn.parameters:",
" - name: num",
" type: integer",
" brooklyn.children:",
" - type: " + ConfigEntityForTest.class.getName(),
" brooklyn.config:",
" refConfig: $brooklyn:scopeRoot().config(\"num\")",
" - type: " + ConfigEntityForTest.class.getName(),
" brooklyn.config:",
" refConfig: $brooklyn:config(\"num\")"); //inherited config
Entity app = createAndStartApplication(
"services:",
"- type: " + BasicApplication.class.getName(),
" brooklyn.children:",
" - type: " + ver(SYMBOLIC_NAME),
" brooklyn.config:",
" num: \"" + testValue + "\"");
Entity scopeRoot = Iterables.getOnlyElement(app.getChildren());
ConfigKey<Object> numKey = ConfigKeys.newConfigKey(Object.class, "num");
assertEquals(scopeRoot.config().get(numKey), testValue);
ConfigKey<Object> refConfigKey = ConfigKeys.newConfigKey(Object.class, "refConfig");
Iterator<Entity> childIter = scopeRoot.getChildren().iterator();
Entity c1 = childIter.next();
assertEquals(c1.config().get(refConfigKey), testValue);
Entity c2 = childIter.next();
assertEquals(c2.config().get(refConfigKey), testValue);
assertFalse(childIter.hasNext());
}
@Test
public void testAppRootParameters() throws Exception {
EntitySpec<? extends Application> spec = createAppSpec(
"brooklyn.parameters:",
"- simple",
"services:",
"- type: " + BasicApplication.class.getName());
List<SpecParameter<?>> inputs = spec.getParameters();
assertEquals(inputs.size(), 1);
SpecParameter<?> firstInput = inputs.get(0);
assertEquals(firstInput.getLabel(), "simple");
}
@Test
public void testAppServiceParameters() throws Exception {
EntitySpec<? extends Application> spec = createAppSpec(
"services:",
"- type: " + BasicApplication.class.getName(),
" brooklyn.parameters:",
" - simple");
List<SpecParameter<?>> inputs = spec.getParameters();
assertEquals(inputs.size(), 1);
SpecParameter<?> firstInput = inputs.get(0);
assertEquals(firstInput.getLabel(), "simple");
}
@SuppressWarnings({"unchecked", "rawtypes"})
private AbstractBrooklynObjectSpec<?, ?> createSpec(CatalogItem<?, ?> item) {
return (AbstractBrooklynObjectSpec<?,?>) catalog.createSpec((CatalogItem)item);
}
private EntitySpec<? extends Application> createAppSpec(String... lines) {
return EntityManagementUtils.createEntitySpecForApplication(mgmt(), joinLines(lines));
}
}