You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ha...@apache.org on 2015/08/05 22:56:06 UTC
[02/20] incubator-brooklyn git commit: Package rename to
org.apache.brooklyn: usage-cli
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74ee6aac/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ClassFinder.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ClassFinder.java b/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ClassFinder.java
new file mode 100644
index 0000000..2ddad9d
--- /dev/null
+++ b/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ClassFinder.java
@@ -0,0 +1,153 @@
+/*
+ * 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.cli.lister;
+
+import java.io.File;
+import java.lang.annotation.Annotation;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.reflections.Reflections;
+import org.reflections.scanners.FieldAnnotationsScanner;
+import org.reflections.scanners.SubTypesScanner;
+import org.reflections.scanners.TypeAnnotationsScanner;
+import org.reflections.util.ConfigurationBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.basic.BrooklynObject;
+import brooklyn.enricher.basic.AbstractEnricher;
+import brooklyn.entity.Application;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.AbstractApplication;
+import brooklyn.entity.basic.AbstractEntity;
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import brooklyn.policy.Enricher;
+import brooklyn.policy.Policy;
+import brooklyn.policy.basic.AbstractPolicy;
+import brooklyn.util.ResourceUtils;
+import brooklyn.util.javalang.UrlClassLoader;
+import brooklyn.util.net.Urls;
+import brooklyn.util.os.Os;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+public class ClassFinder {
+
+ private static final Logger log = LoggerFactory.getLogger(ClassFinder.class);
+
+ private static final Collection<Class<?>> BORING = ImmutableList.<Class<?>>of(
+ Entity.class,
+ AbstractEntity.class,
+ SoftwareProcessImpl.class,
+ Application.class,
+ AbstractApplication.class,
+ Policy.class,
+ Enricher.class,
+ AbstractPolicy.class,
+ AbstractEnricher.class);
+
+ public static Predicate<Class<?>> notBoring() {
+ return new Predicate<Class<?>>() {
+ public boolean apply(Class<?> input) {
+ return (input != null && !BORING.contains(input));
+ }
+ };
+ }
+
+ public static Predicate<Class<?>> withAnnotation(final Class<? extends Annotation> annotation) {
+ return new Predicate<Class<?>>() {
+ public boolean apply(Class<?> input) {
+ return (input != null && input.getAnnotation(annotation) != null);
+ }
+ };
+ }
+
+ public static Predicate<? super Class<? extends BrooklynObject>> withClassNameMatching(final String typeRegex) {
+ return new Predicate<Class<?>>() {
+ public boolean apply(Class<?> input) {
+ return (input != null && input.getName() != null && input.getName().matches(typeRegex));
+ }
+ };
+ }
+
+ /** finds a jar at a url, or for directories, jars under a path */
+ @Beta
+ public static List<URL> toJarUrls(String url) throws MalformedURLException {
+ if (url==null) throw new NullPointerException("Cannot read from null");
+ if (url=="") throw new NullPointerException("Cannot read from empty string");
+
+ List<URL> result = Lists.newArrayList();
+
+ String protocol = Urls.getProtocol(url);
+ if (protocol!=null) {
+ // it's a URL - easy
+ if ("file".equals(protocol)) {
+ url = ResourceUtils.tidyFileUrl(url);
+ }
+ result.add(new URL(url));
+ } else {
+ // treat as file
+ String tidiedPath = Os.tidyPath(url);
+ File tidiedFile = new File(tidiedPath);
+ if (tidiedFile.isDirectory()) {
+ List<File> toscan = Lists.newLinkedList();
+ toscan.add(tidiedFile);
+ while (toscan.size() > 0) {
+ File file = toscan.remove(0);
+ if (file.isFile()) {
+ if (file.getName().toLowerCase().endsWith(".jar")) {
+ result.add(new URL("file://"+file.getAbsolutePath()));
+ }
+ } else if (file.isDirectory()) {
+ for (File subfile : file.listFiles()) {
+ toscan.add(subfile);
+ }
+ } else {
+ log.info("Cannot read "+file+"; not a file or directory");
+ }
+ }
+ } else {
+ result.add(tidiedFile.toURI().toURL());
+ }
+ }
+
+ return result;
+ }
+
+ public static <T extends BrooklynObject> Set<Class<? extends T>> findClasses(Collection<URL> urls, Class<T> clazz) {
+ ClassLoader classLoader = new UrlClassLoader(urls.toArray(new URL[urls.size()]));
+
+ Reflections reflections = new ConfigurationBuilder()
+ .addClassLoader(classLoader)
+ .addScanners(new SubTypesScanner(), new TypeAnnotationsScanner(), new FieldAnnotationsScanner())
+ .addUrls(urls)
+ .build();
+
+ Set<Class<? extends T>> types = reflections.getSubTypesOf(clazz);
+
+ return types;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74ee6aac/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java b/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
new file mode 100644
index 0000000..3912dd9
--- /dev/null
+++ b/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
@@ -0,0 +1,173 @@
+/*
+ * 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.cli.lister;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.basic.BrooklynDynamicType;
+import brooklyn.basic.BrooklynObject;
+import brooklyn.basic.BrooklynType;
+import brooklyn.basic.BrooklynTypes;
+import org.apache.brooklyn.catalog.Catalog;
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.Effector;
+import brooklyn.entity.EntityType;
+import brooklyn.entity.basic.BrooklynConfigKeys;
+import brooklyn.event.Sensor;
+import brooklyn.location.LocationResolver;
+import brooklyn.rest.domain.EffectorSummary;
+import brooklyn.rest.domain.EntityConfigSummary;
+import brooklyn.rest.domain.SensorSummary;
+import brooklyn.rest.domain.SummaryComparators;
+import brooklyn.rest.transform.EffectorTransformer;
+import brooklyn.rest.transform.EntityTransformer;
+import brooklyn.rest.transform.SensorTransformer;
+import brooklyn.util.exceptions.RuntimeInterruptedException;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+public class ItemDescriptors {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ItemDescriptors.class);
+
+ public static List<Map<String, Object>> toItemDescriptors(Iterable<? extends Class<? extends BrooklynObject>> types, boolean headingsOnly) {
+ return toItemDescriptors(types, headingsOnly, null);
+ }
+
+ public static List<Map<String, Object>> toItemDescriptors(Iterable<? extends Class<? extends BrooklynObject>> types, boolean headingsOnly, final String sortField) {
+ List<Map<String, Object>> itemDescriptors = Lists.newArrayList();
+
+ for (Class<? extends BrooklynObject> type : types) {
+ try {
+ Map<String, Object> itemDescriptor = toItemDescriptor(type, headingsOnly);
+ itemDescriptors.add(itemDescriptor);
+ } catch (Throwable throwable) {
+ if (throwable instanceof InterruptedException)
+ throw new RuntimeInterruptedException((InterruptedException) throwable);
+ if (throwable instanceof RuntimeInterruptedException)
+ throw (RuntimeInterruptedException) throwable;
+
+ LOG.warn("Could not load "+type+": "+throwable);
+ }
+ }
+
+ if (!Strings.isNullOrEmpty(sortField)) {
+ Collections.sort(itemDescriptors, new Comparator<Map<String, Object>>() {
+ @Override public int compare(Map<String, Object> id1, Map<String, Object> id2) {
+ Object o1 = id1.get(sortField);
+ Object o2 = id2.get(sortField);
+ if (o1 == null) {
+ return o2 == null ? 0 : 1;
+ }
+ if (o2 == null) {
+ return -1;
+ }
+ return o1.toString().compareTo(o2.toString());
+ }
+ });
+ }
+
+ return itemDescriptors;
+ }
+
+ public static Map<String,Object> toItemDescriptor(Class<? extends BrooklynObject> clazz, boolean headingsOnly) {
+ BrooklynDynamicType<?, ?> dynamicType = BrooklynTypes.getDefinedBrooklynType(clazz);
+ BrooklynType type = dynamicType.getSnapshot();
+ ConfigKey<?> version = dynamicType.getConfigKey(BrooklynConfigKeys.SUGGESTED_VERSION.getName());
+
+ Map<String,Object> result = Maps.newLinkedHashMap();
+
+ result.put("type", clazz.getName());
+ if (version != null) {
+ result.put("defaultVersion", version.getDefaultValue());
+ }
+
+ Catalog catalogAnnotation = clazz.getAnnotation(Catalog.class);
+ if (catalogAnnotation != null) {
+ result.put("name", catalogAnnotation.name());
+ result.put("description", catalogAnnotation.description());
+ result.put("iconUrl", catalogAnnotation.iconUrl());
+ }
+
+ Deprecated deprecatedAnnotation = clazz.getAnnotation(Deprecated.class);
+ if (deprecatedAnnotation != null) {
+ result.put("deprecated", true);
+ }
+
+ if (!headingsOnly) {
+ Set<EntityConfigSummary> config = Sets.newTreeSet(SummaryComparators.nameComparator());
+ Set<SensorSummary> sensors = Sets.newTreeSet(SummaryComparators.nameComparator());
+ Set<EffectorSummary> effectors = Sets.newTreeSet(SummaryComparators.nameComparator());
+
+ for (ConfigKey<?> x: type.getConfigKeys()) {
+ config.add(EntityTransformer.entityConfigSummary(x, dynamicType.getConfigKeyField(x.getName())));
+ }
+ result.put("config", config);
+
+ if (type instanceof EntityType) {
+ for (Sensor<?> x: ((EntityType)type).getSensors())
+ sensors.add(SensorTransformer.sensorSummaryForCatalog(x));
+ result.put("sensors", sensors);
+
+ for (Effector<?> x: ((EntityType)type).getEffectors())
+ effectors.add(EffectorTransformer.effectorSummaryForCatalog(x));
+ result.put("effectors", effectors);
+ }
+ }
+
+ return result;
+ }
+
+ public static Object toItemDescriptors(List<LocationResolver> resolvers) {
+ return toItemDescriptors(resolvers, false);
+ }
+
+ public static Object toItemDescriptors(List<LocationResolver> resolvers, Boolean sort) {
+ List<Object> result = Lists.newArrayList();
+ for (LocationResolver resolver : resolvers) {
+ result.add(toItemDescriptor(resolver));
+ }
+ if (sort) {
+ Collections.sort(result, new Comparator<Object>() {
+ @Override public int compare(Object o1, Object o2) {
+ String s1 = o1 == null ? "" : o1.toString();
+ String s2 = o2 == null ? "" : o2.toString();
+ return s1.compareTo(s2);
+ }
+ });
+ }
+ return result;
+ }
+
+ public static Object toItemDescriptor(LocationResolver resolver) {
+ // TODO Get javadoc of LocationResolver? Could use docklet? But that would give dependency here
+ // on com.sun.javadoc.*
+ return resolver.getPrefix();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74ee6aac/usage/cli/src/test/java/brooklyn/cli/CliTest.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/test/java/brooklyn/cli/CliTest.java b/usage/cli/src/test/java/brooklyn/cli/CliTest.java
deleted file mode 100644
index 9bf173c..0000000
--- a/usage/cli/src/test/java/brooklyn/cli/CliTest.java
+++ /dev/null
@@ -1,604 +0,0 @@
-/*
- * 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 brooklyn.cli;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-import groovy.lang.GroovyClassLoader;
-import io.airlift.command.Cli;
-import io.airlift.command.Command;
-import io.airlift.command.ParseException;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Pattern;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.cli.AbstractMain.BrooklynCommand;
-import brooklyn.cli.AbstractMain.BrooklynCommandCollectingArgs;
-import brooklyn.cli.AbstractMain.HelpCommand;
-import brooklyn.cli.Main.AppShutdownHandler;
-import brooklyn.cli.Main.GeneratePasswordCommand;
-import brooklyn.cli.Main.LaunchCommand;
-import brooklyn.entity.Entity;
-import brooklyn.entity.basic.AbstractApplication;
-import brooklyn.entity.basic.AbstractEntity;
-import brooklyn.entity.basic.ApplicationBuilder;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.proxying.EntityProxy;
-import brooklyn.entity.proxying.ImplementedBy;
-import brooklyn.entity.trait.Startable;
-import brooklyn.location.Location;
-import brooklyn.location.basic.SimulatedLocation;
-import brooklyn.test.Asserts;
-import brooklyn.test.entity.LocalManagementContextForTests;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.exceptions.FatalConfigurationRuntimeException;
-import brooklyn.util.exceptions.UserFacingException;
-import brooklyn.util.time.Duration;
-
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.io.Files;
-
-public class CliTest {
-
- private static final Logger LOG = LoggerFactory.getLogger(CliTest.class);
-
- // See testInvokeGroovyScript test for usage
- public static final AtomicBoolean GROOVY_INVOKED = new AtomicBoolean(false);
-
- private ExecutorService executor;
- private StartableApplication app;
- private static volatile ExampleEntity exampleEntity;
-
- // static so that they can be set from the static classes ExampleApp and ExampleEntity
- private static volatile boolean exampleAppRunning;
- private static volatile boolean exampleAppConstructed;
- private static volatile boolean exampleEntityRunning;
-
- @BeforeMethod(alwaysRun=true)
- public void setUp() throws Exception {
- executor = Executors.newCachedThreadPool();
- exampleAppConstructed = false;
- exampleAppRunning = false;
- exampleEntityRunning = false;
- }
-
- @AfterMethod(alwaysRun=true)
- public void tearDown() throws Exception {
- if (executor != null) executor.shutdownNow();
- if (app != null) Entities.destroyAll(app.getManagementContext());
- if (exampleEntity != null && exampleEntity.getApplication() != null) Entities.destroyAll(exampleEntity.getApplication().getManagementContext());
- }
-
- @Test
- public void testLoadApplicationFromClasspath() throws Exception {
- String appName = ExampleApp.class.getName();
- Object appBuilder = loadApplicationFromClasspathOrParse(appName);
- assertTrue(appBuilder instanceof ApplicationBuilder, "app="+appBuilder);
- assertAppWrappedInBuilder((ApplicationBuilder)appBuilder, ExampleApp.class.getCanonicalName());
- }
-
- @Test
- public void testLoadApplicationBuilderFromClasspath() throws Exception {
- String appName = ExampleAppBuilder.class.getName();
- Object appBuilder = loadApplicationFromClasspathOrParse(appName);
- assertTrue(appBuilder instanceof ExampleAppBuilder, "app="+appBuilder);
- }
-
- @Test
- public void testLoadEntityFromClasspath() throws Exception {
- String entityName = ExampleEntity.class.getName();
- Object appBuilder = loadApplicationFromClasspathOrParse(entityName);
- assertTrue(appBuilder instanceof ApplicationBuilder, "app="+appBuilder);
-
- app = ((ApplicationBuilder)appBuilder).manage();
- Collection<Entity> entities = app.getChildren();
- assertEquals(entities.size(), 1, "entities="+entities);
- assertTrue(Iterables.getOnlyElement(entities) instanceof ExampleEntity, "entities="+entities+"; ifs="+Iterables.getOnlyElement(entities).getClass().getInterfaces());
- assertTrue(Iterables.getOnlyElement(entities) instanceof EntityProxy, "entities="+entities);
- }
-
- @Deprecated // Tests deprecated approach of using impl directly
- @Test
- public void testLoadEntityImplFromClasspath() throws Exception {
- String entityName = ExampleEntityImpl.class.getName();
- Object appBuilder = loadApplicationFromClasspathOrParse(entityName);
- assertTrue(appBuilder instanceof ApplicationBuilder, "app="+appBuilder);
-
- app = ((ApplicationBuilder)appBuilder).manage();
- Collection<Entity> entities = app.getChildren();
- assertEquals(entities.size(), 1, "entities="+entities);
- assertEquals(Iterables.getOnlyElement(entities).getEntityType().getName(), ExampleEntity.class.getCanonicalName(), "entities="+entities);
- assertTrue(Iterables.getOnlyElement(entities) instanceof EntityProxy, "entities="+entities);
- }
-
- @Test
- public void testLoadApplicationByParsingGroovyFile() throws Exception {
- String appName = "ExampleAppInFile.groovy"; // file found in src/test/resources (contains empty app)
- Object appBuilder = loadApplicationFromClasspathOrParse(appName);
- assertTrue(appBuilder instanceof ApplicationBuilder, "app="+appBuilder);
- assertAppWrappedInBuilder((ApplicationBuilder)appBuilder, "ExampleAppInFile");
- }
-
- private Object loadApplicationFromClasspathOrParse(String appName) throws Exception {
- LaunchCommand launchCommand = new Main.LaunchCommand();
- ResourceUtils resourceUtils = ResourceUtils.create(this);
- GroovyClassLoader loader = new GroovyClassLoader(CliTest.class.getClassLoader());
- return launchCommand.loadApplicationFromClasspathOrParse(resourceUtils, loader, appName);
- }
-
- private void assertAppWrappedInBuilder(ApplicationBuilder builder, String expectedAppTypeName) {
- StartableApplication app = builder.manage();
- try {
- String typeName = app.getEntityType().getName();
- assertEquals(typeName, expectedAppTypeName, "app="+app+"; typeName="+typeName);
- } finally {
- Entities.destroyAll(app.getManagementContext());
- }
- }
-
- @Test
- public void testInvokeGroovyScript() throws Exception {
- File groovyFile = File.createTempFile("testinvokegroovy", "groovy");
- try {
- String contents = CliTest.class.getCanonicalName()+".GROOVY_INVOKED.set(true);";
- Files.write(contents.getBytes(), groovyFile);
-
- LaunchCommand launchCommand = new Main.LaunchCommand();
- ResourceUtils resourceUtils = ResourceUtils.create(this);
- GroovyClassLoader loader = new GroovyClassLoader(CliTest.class.getClassLoader());
- launchCommand.execGroovyScript(resourceUtils, loader, groovyFile.toURI().toString());
- assertTrue(GROOVY_INVOKED.get());
-
- } finally {
- groovyFile.delete();
- GROOVY_INVOKED.set(false);
- }
- }
-
- @Test
- public void testStopAllApplications() throws Exception {
- LaunchCommand launchCommand = new Main.LaunchCommand();
- ExampleApp app = new ExampleApp();
- try {
- Entities.startManagement(app);
- app.start(ImmutableList.of(new SimulatedLocation()));
- assertTrue(app.running);
-
- launchCommand.stopAllApps(ImmutableList.of(app));
- assertFalse(app.running);
- } finally {
- Entities.destroyAll(app.getManagementContext());
- }
- }
-
- @Test
- public void testWaitsForInterrupt() throws Exception {
- final AppShutdownHandler listener = new AppShutdownHandler();
- Thread t = new Thread(new Runnable() {
- @Override public void run() {
- listener.waitOnShutdownRequest();
- }});
-
- t.start();
- t.join(100);
- assertTrue(t.isAlive());
-
- t.interrupt();
- t.join(10*1000);
- assertFalse(t.isAlive());
- }
-
- protected Cli<BrooklynCommand> buildCli() {
- return new Main().cliBuilder().build();
- }
-
- @Test
- public void testLaunchCommandParsesArgs() throws ParseException {
- BrooklynCommand command = buildCli().parse("launch",
- "--app", "my.App",
- "--location", "localhost",
- "--port", "1234",
- "--bindAddress", "myhostname",
- "--noConsole", "--noConsoleSecurity", "--stopOnKeyPress",
- "--localBrooklynProperties", "/path/to/myprops",
- LaunchCommand.PERSIST_OPTION, LaunchCommand.PERSIST_OPTION_REBIND,
- "--persistenceDir", "/path/to/mypersist",
- LaunchCommand.HA_OPTION, LaunchCommand.HA_OPTION_STANDBY);
- assertTrue(command instanceof LaunchCommand, ""+command);
- String details = command.toString();
- assertTrue(details.contains("app=my.App"), details);
- assertTrue(details.contains("script=null"), details);
- assertTrue(details.contains("location=localhost"), details);
- assertTrue(details.contains("port=1234"), details);
- assertTrue(details.contains("bindAddress=myhostname"), details);
- assertTrue(details.contains("noConsole=true"), details);
- assertTrue(details.contains("noConsoleSecurity=true"), details);
- assertTrue(details.contains("stopOnKeyPress=true"), details);
- assertTrue(details.contains("localBrooklynProperties=/path/to/myprops"), details);
- assertTrue(details.contains("persist=rebind"), details);
- assertTrue(details.contains("persistenceDir=/path/to/mypersist"), details);
- assertTrue(details.contains("highAvailability=standby"), details);
- }
-
- @Test
- public void testLaunchCommandUsesDefaults() throws ParseException {
- BrooklynCommand command = buildCli().parse("launch");
- assertTrue(command instanceof LaunchCommand, ""+command);
- String details = command.toString();
- assertTrue(details.contains("app=null"), details);
- assertTrue(details.contains("script=null"), details);
- assertTrue(details.contains("location=null"), details);
- assertTrue(details.contains("port=null"), details);
- assertTrue(details.contains("noConsole=false"), details);
- assertTrue(details.contains("noConsoleSecurity=false"), details);
- assertTrue(details.contains("stopWhichAppsOnShutdown=theseIfNotPersisted"), details);
- assertTrue(details.contains("stopOnKeyPress=false"), details);
- assertTrue(details.contains("localBrooklynProperties=null"), details);
- assertTrue(details.contains("persist=disabled"), details);
- assertTrue(details.contains("persistenceDir=null"), details);
- assertTrue(details.contains("highAvailability=auto"), details);
- }
-
- @Test
- public void testLaunchCommandComplainsWithInvalidArgs() {
- Cli<BrooklynCommand> cli = buildCli();
- try {
- BrooklynCommand command = cli.parse("launch", "invalid");
- command.call();
- Assert.fail("Should have thrown exception; instead got "+command);
- } catch (ParseException e) {
- /* expected */
- } catch (Exception e) {
- throw Exceptions.propagate(e);
- }
- }
-
- @Test
- public void testAppOptionIsOptional() throws ParseException {
- Cli<BrooklynCommand> cli = buildCli();
- cli.parse("launch", "blah", "my.App");
- }
-
- public void testHelpCommand() {
- Cli<BrooklynCommand> cli = buildCli();
- BrooklynCommand command = cli.parse("help");
- assertTrue(command instanceof HelpCommand);
- command = cli.parse();
- assertTrue(command instanceof HelpCommand);
- }
-
- @Test
- public void testLaunchWillStartAppWhenGivenImpl() throws Exception {
- Cli<BrooklynCommand> cli = buildCli();
- BrooklynCommand command = cli.parse("launch", "--noConsole", "--app", ExampleApp.class.getName(), "--location", "localhost");
- submitCommandAndAssertRunnableSucceeds(command, new Runnable() {
- public void run() {
- assertTrue(exampleAppConstructed);
- assertTrue(exampleAppRunning);
- }
- });
- }
-
- @Test
- public void testLaunchStartsYamlApp() throws Exception {
- Cli<BrooklynCommand> cli = buildCli();
- BrooklynCommand command = cli.parse("launch", "--noConsole", "--app", "example-app-no-location.yaml", "--location", "localhost");
- submitCommandAndAssertRunnableSucceeds(command, new Runnable() {
- public void run() {
- assertTrue(exampleEntityRunning);
- }
- });
- }
-
- @Test
- public void testLaunchStartsYamlAppWithCommandLineLocation() throws Exception {
- Cli<BrooklynCommand> cli = buildCli();
- BrooklynCommand command = cli.parse("launch", "--noConsole", "--app", "example-app-no-location.yaml", "--location", "localhost:(name=testLocalhost)");
- submitCommandAndAssertRunnableSucceeds(command, new Runnable() {
- public void run() {
- assertTrue(exampleEntityRunning);
- assertTrue(Iterables.getOnlyElement(exampleEntity.getApplication().getLocations()).getDisplayName().equals("testLocalhost"));
- }
- });
- }
-
- @Test
- public void testLaunchStartsYamlAppWithYamlAppLocation() throws Exception {
- Cli<BrooklynCommand> cli = buildCli();
- BrooklynCommand command = cli.parse("launch", "--noConsole", "--app", "example-app-app-location.yaml");
- submitCommandAndAssertRunnableSucceeds(command, new Runnable() {
- public void run() {
- assertTrue(exampleEntityRunning);
- assertTrue(Iterables.getOnlyElement(exampleEntity.getApplication().getLocations()).getDisplayName().equals("appLocalhost"));
- }
- });
- }
-
- @Test
- public void testLaunchStartsYamlAppWithYamlAndAppCliLocation() throws Exception {
- Cli<BrooklynCommand> cli = buildCli();
- BrooklynCommand command = cli.parse("launch", "--noConsole", "--app", "example-app-app-location.yaml", "--location", "localhost");
- submitCommandAndAssertRunnableSucceeds(command, new Runnable() {
- public void run() {
- assertTrue(exampleEntityRunning);
- assertTrue(Iterables.getFirst(exampleEntity.getApplication().getLocations(), null).getDisplayName().equals("appLocalhost"));
- }
- });
- }
-
- @Test
- public void testGeneratePasswordCommandParsed() throws Exception {
- Cli<BrooklynCommand> cli = buildCli();
- BrooklynCommand command = cli.parse("generate-password", "--user", "myname");
-
- assertTrue(command instanceof GeneratePasswordCommand);
- }
-
- @Test
- public void testGeneratePasswordFromStdin() throws Exception {
- List<String> stdoutLines = runCommand(ImmutableList.of("generate-password", "--user", "myname", "--stdin"), "mypassword\nmypassword\n");
-
- System.out.println(stdoutLines);
- }
-
- @Test
- public void testGeneratePasswordFailsIfPasswordsDontMatch() throws Throwable {
- Throwable exception = runCommandExpectingException(ImmutableList.of("generate-password", "--user", "myname", "--stdin"), "mypassword\ndifferentpassword\n");
- if (exception instanceof UserFacingException && exception.toString().contains("Passwords did not match")) {
- // success
- } else {
- throw new Exception(exception);
- }
- }
-
- @Test
- public void testGeneratePasswordFailsIfNoConsole() throws Throwable {
- Throwable exception = runCommandExpectingException(ImmutableList.of("generate-password", "--user", "myname"), "");
- if (exception instanceof FatalConfigurationRuntimeException && exception.toString().contains("No console")) {
- // success
- } else {
- throw new Exception(exception);
- }
- }
-
- @Test
- public void testGeneratePasswordFailsIfPasswordBlank() throws Throwable {
- Throwable exception = runCommandExpectingException(ImmutableList.of("generate-password", "--user", "myname", "--stdin"), "\n\n");
- if (exception instanceof UserFacingException && exception.toString().contains("Password must not be blank")) {
- // success
- } else {
- throw new Exception(exception);
- }
- }
-
- @Test
- public void testInfoShowsDefaultBanner() throws Exception {
- List<String> stdoutLines = runCommand(ImmutableList.of("info"), "");
-
- for (String line : Splitter.on("\n").split(Main.DEFAULT_BANNER)) {
- assertTrue(stdoutLines.contains(line), "out="+stdoutLines);
- }
- }
-
- @Test
- public void testInfoSupportsCustomizedBanner() throws Exception {
- String origBanner = Main.banner;
- String origBannerFirstLine = Iterables.get(Splitter.on("\n").split(Main.DEFAULT_BANNER), 0);
- try {
- String customBanner = "My Custom Banner";
- Main.banner = customBanner;
- List<String> stdoutLines = runCommand(ImmutableList.of("info"), "");
-
- assertTrue(stdoutLines.contains(customBanner), "out="+stdoutLines);
- assertFalse(stdoutLines.contains(origBannerFirstLine), "out="+stdoutLines);
- } finally {
- Main.banner = origBanner;
- }
- }
-
- @Test
- public void testCanCustomiseInfoCommand() throws Exception {
- Main main = new Main() {
- protected Class<? extends BrooklynCommand> cliInfoCommand() {
- return CustomInfoCommand.class;
- }
- };
- List<String> stdoutLines = runCommand(main.cliBuilder().build(), ImmutableList.of("info"), "");
- assertTrue(stdoutLines.contains("My Custom Info"), "out="+stdoutLines);
- }
-
- @Command(name = "info", description = "Display information about brooklyn")
- public static class CustomInfoCommand extends BrooklynCommandCollectingArgs {
- @Override
- public Void call() throws Exception {
- System.out.println("My Custom Info");
- return null;
- }
- }
-
- @Test
- public void testCanCustomiseLaunchCommand() throws Exception {
- Main main = new Main() {
- protected Class<? extends BrooklynCommand> cliLaunchCommand() {
- return CustomLaunchCommand.class;
- }
- };
- List<String> stdoutLines = runCommand(main.cliBuilder().build(), ImmutableList.of("launch"), "");
- assertTrue(stdoutLines.contains("My Custom Launch"), "out="+stdoutLines);
- }
-
- @Command(name = "launch", description = "Starts a server, optionally with applications")
- public static class CustomLaunchCommand extends BrooklynCommandCollectingArgs {
- @Override
- public Void call() throws Exception {
- System.out.println("My Custom Launch");
- return null;
- }
- }
-
- protected Throwable runCommandExpectingException(Iterable<String> args, String input) throws Exception {
- try {
- List<String> stdout = runCommand(args, input);
- fail("Expected exception, but got stdout="+stdout);
- return null;
- } catch (ExecutionException e) {
- return e.getCause();
- }
- }
-
- protected List<String> runCommand(Iterable<String> args, String input) throws Exception {
- Cli<BrooklynCommand> cli = buildCli();
- return runCommand(cli, args, input);
- }
-
- protected List<String> runCommand(Cli<BrooklynCommand> cli, Iterable<String> args, String input) throws Exception {
- final BrooklynCommand command = cli.parse(args);
-
- final AtomicReference<Exception> exception = new AtomicReference<Exception>();
- Thread t= new Thread(new Runnable() {
- public void run() {
- try {
- command.call();
- } catch (Exception e) {
- exception.set(e);
- throw Exceptions.propagate(e);
- }
- }});
-
- InputStream origIn = System.in;
- PrintStream origOut = System.out;
- try {
- InputStream stdin = new ByteArrayInputStream(input.getBytes());
- System.setIn(stdin);
-
- ByteArrayOutputStream stdoutBytes = new ByteArrayOutputStream();
- PrintStream stdout = new PrintStream(stdoutBytes);
- System.setOut(stdout);
-
- t.start();
-
- t.join(10*1000);
- assertFalse(t.isAlive());
-
- if (exception.get() != null) {
- throw new ExecutionException(exception.get());
- }
-
- return ImmutableList.copyOf(Splitter.on(Pattern.compile("\r?\n")).split(new String(stdoutBytes.toByteArray())));
- } finally {
- System.setIn(origIn);
- System.setOut(origOut);
- t.interrupt();
- }
- }
-
- private void submitCommandAndAssertRunnableSucceeds(final BrooklynCommand command, Runnable runnable) {
- if (command instanceof LaunchCommand) {
- ((LaunchCommand)command).useManagementContext(new LocalManagementContextForTests());
- }
- executor.submit(new Callable<Void>() {
- public Void call() throws Exception {
- try {
- LOG.info("Calling command: "+command);
- command.call();
- return null;
- } catch (Throwable t) {
- LOG.error("Error executing command: "+t, t);
- throw Exceptions.propagate(t);
- }
- }});
-
- Asserts.succeedsEventually(MutableMap.of("timeout", Duration.ONE_MINUTE), runnable);
- }
-
- // An empty app to be used for testing
- public static class ExampleApp extends AbstractApplication {
- volatile boolean running;
- volatile boolean constructed;
-
- @Override public void init() {
- super.init();
- constructed = true;
- exampleAppConstructed = true;
- }
- @Override public void start(Collection<? extends Location> locations) {
- super.start(locations);
- running = true;
- exampleAppRunning = true;
- }
- @Override public void stop() {
- super.stop();
- running = false;
- exampleAppRunning = false;
- }
- }
-
- // An empty entity to be used for testing
- @ImplementedBy(ExampleEntityImpl.class)
- public static interface ExampleEntity extends Entity, Startable {
- }
-
- public static class ExampleEntityImpl extends AbstractEntity implements ExampleEntity {
- public ExampleEntityImpl() {
- super();
- exampleEntity = this;
- }
- @Override public void start(Collection<? extends Location> locations) {
- exampleEntityRunning = true;
- }
- @Override public void stop() {
- exampleEntityRunning = false;
- }
- @Override public void restart() {
- }
- }
-
- // An empty app builder to be used for testing
- public static class ExampleAppBuilder extends ApplicationBuilder {
- @Override protected void doBuild() {
- // no-op
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74ee6aac/usage/cli/src/test/java/brooklyn/cli/CloudExplorerLiveTest.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/test/java/brooklyn/cli/CloudExplorerLiveTest.java b/usage/cli/src/test/java/brooklyn/cli/CloudExplorerLiveTest.java
deleted file mode 100644
index 6069f74..0000000
--- a/usage/cli/src/test/java/brooklyn/cli/CloudExplorerLiveTest.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * 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 brooklyn.cli;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-import io.airlift.command.Cli;
-import io.airlift.command.ParseException;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.util.List;
-
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.cli.AbstractMain.BrooklynCommand;
-
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-
-public class CloudExplorerLiveTest {
-
- private String stdout;
- private String stderr;
-
- @AfterMethod(alwaysRun=true)
- public void tearDown() {
- stdout = null;
- stderr = null;
- }
-
- @Test
- public void testNoArgsThrows() throws Exception {
- try {
- call(new String[0]);
- Assert.fail("No args should fail");
- } catch (ParseException e) {
- Assert.assertTrue(e.toString().contains("No command specified"), ""+e);
- }
- }
-
- // A user running these tests might not have any instances; so don't assert that there will be one
- @Test(groups={"Live", "Live-sanity"})
- public void testListInstances() throws Exception {
- call("cloud-compute", "list-instances", "--location", "jclouds:aws-ec2:eu-west-1");
-
- String errmsg = "stdout="+stdout+"; stderr="+stderr;
-
- List<String> lines = assertAndStipSingleLocationHeader(stdout);
- assertTrue(lines.get(0).equals("Instances {"), errmsg);
- assertTrue(lines.get(lines.size()-1).equals("}"), errmsg);
- assertTrue(stderr.isEmpty(), errmsg);
- }
-
- @Test(groups={"Live", "Live-sanity"})
- public void testListImages() throws Exception {
- call("cloud-compute", "list-images", "--location", "jclouds:softlayer:ams01");
-
- String errmsg = "stdout="+stdout+"; stderr="+stderr;
-
- // FIXME Now has location details pre-amble; fix assertions
- List<String> lines = assertAndStipSingleLocationHeader(stdout);
- assertTrue(lines.get(0).equals("Images {"), errmsg);
- assertTrue(lines.get(lines.size()-1).equals("}"), errmsg);
- assertTrue(stderr.isEmpty(), errmsg);
-
- List<String> imageLines = lines.subList(1, lines.size()-1);
- assertTrue(imageLines.size() > 0, errmsg);
- assertTrue(imageLines.get(0).matches(".*id=.*providerId=.*os=.*description=.*"), "line="+imageLines.get(0)+"; "+errmsg);
- }
-
- @Test(groups={"Live", "Live-sanity"})
- public void testListHardwareProfiles() throws Exception {
- call("cloud-compute", "list-hardware-profiles", "--location", "jclouds:softlayer:ams01");
-
- String errmsg = "stdout="+stdout+"; stderr="+stderr;
-
- // FIXME Now has location details pre-amble; fix assertions
- List<String> lines = assertAndStipSingleLocationHeader(stdout);
- assertTrue(lines.get(0).equals("Hardware Profiles {"), errmsg);
- assertTrue(lines.get(lines.size()-1).equals("}"), errmsg);
- assertTrue(stderr.isEmpty(), errmsg);
-
- List<String> hardwareProfileLines = lines.subList(1, lines.size()-1);
- assertTrue(hardwareProfileLines.size() > 0, errmsg);
- assertTrue(hardwareProfileLines.get(0).matches(".*cpu=.*memory=.*processors=.*"), "line="+hardwareProfileLines.get(0)+"; "+errmsg);
- }
-
- @Test(groups={"Live", "Live-sanity"})
- public void testGetImage() throws Exception {
- call("cloud-compute", "get-image", "--location", "jclouds:softlayer:ams01", "CENTOS_6_64");
-
- String errmsg = "stdout="+stdout+"; stderr="+stderr;
-
- // FIXME Now has location details pre-amble; fix assertions
- List<String> lines = assertAndStipSingleLocationHeader(stdout);
- assertTrue(lines.get(0).equals("Image CENTOS_6_64 {"), errmsg);
- assertTrue(lines.get(lines.size()-1).equals("}"), errmsg);
- assertTrue(stderr.isEmpty(), errmsg);
-
- List<String> imageLines = lines.subList(1, lines.size()-1);
- assertTrue(imageLines.size() > 0, errmsg);
- assertTrue(imageLines.get(0).matches(".*id=.*providerId=.*os=.*description=.*"), "line="+imageLines.get(0)+"; "+errmsg);
- }
-
- @Test(groups={"Live", "Live-sanity"})
- public void testGetDefaultTemplate() throws Exception {
- call("cloud-compute", "default-template", "--location", "jclouds:softlayer:ams01");
-
- String errmsg = "stdout="+stdout+"; stderr="+stderr;
-
- // FIXME Now has location details pre-amble; fix assertions
- List<String> lines = assertAndStipSingleLocationHeader(stdout);
- assertTrue(lines.get(0).equals("Default template {"), errmsg);
- assertTrue(lines.get(lines.size()-1).equals("}"), errmsg);
- assertTrue(stderr.isEmpty(), errmsg);
-
- List<String> imageLines = lines.subList(1, lines.size()-1);
- assertTrue(imageLines.size() > 0, errmsg);
- assertTrue(imageLines.get(0).matches("\tImage.*id=.*providerId=.*os=.*description=.*"), "line="+imageLines.get(0)+"; "+errmsg);
- assertTrue(imageLines.get(1).matches("\tHardware.*cpu=.*memory=.*processors=.*"), "line="+imageLines.get(1)+"; "+errmsg);
- assertTrue(imageLines.get(2).matches("\tLocation.*scope=.*"), "line="+imageLines.get(2)+"; "+errmsg);
- assertTrue(imageLines.get(3).matches("\tOptions.*"), "line="+imageLines.get(3)+"; "+errmsg);
- }
-
- /**
- * Expects in brooklyn.properties:
- * brooklyn.location.named.softlayer-swift-ams01=jclouds:swift:https://ams01.objectstorage.softlayer.net/auth/v1.0
- * brooklyn.location.named.softlayer-swift-ams01.identity=ABCDEFGH:myusername
- * brooklyn.location.named.softlayer-swift-ams01.credential=1234567890...
- */
- @Test(groups={"Live", "Live-sanity"})
- public void testListContainers() throws Exception {
- call("cloud-blobstore", "list-containers", "--location", "named:softlayer-swift-ams01");
-
- String errmsg = "stdout="+stdout+"; stderr="+stderr;
-
- // FIXME Now has location details pre-amble; fix assertions
- List<String> lines = assertAndStipSingleLocationHeader(stdout);
- assertTrue(lines.get(0).equals("Containers {"), errmsg);
- assertTrue(lines.get(lines.size()-1).equals("}"), errmsg);
- assertTrue(stderr.isEmpty(), errmsg);
- }
-
- protected void call(String... args) throws Exception {
- call(new ByteArrayInputStream(new byte[0]), args);
- }
-
- protected void call(InputStream instream, String... args) throws Exception {
- ByteArrayOutputStream stdoutStream = new ByteArrayOutputStream();
- ByteArrayOutputStream stderrStream = new ByteArrayOutputStream();
-
- Cli<BrooklynCommand> parser = new Main().cliBuilder().build();
-
- BrooklynCommand command = parser.parse(args);
- command.stdout = new PrintStream(stdoutStream);
- command.stderr = new PrintStream(stderrStream);
- command.stdin = instream;
- try {
- command.call();
- } finally {
- stdout = new String(stdoutStream.toByteArray());
- stderr = new String(stderrStream.toByteArray());
- }
- }
-
- private List<String> assertAndStipSingleLocationHeader(String stdout) {
- List<String> lines = ImmutableList.copyOf(Splitter.on("\n").omitEmptyStrings().split(stdout));
-
- String errmsg = "lines="+lines;
-
- int nextLineCount = 0;
- assertEquals(lines.get(nextLineCount++), "Location {", errmsg);
- assertEquals(lines.get(lines.size()-1), "}", errmsg);
- assertTrue(lines.get(nextLineCount++).startsWith("\tprovider: "), errmsg);
- assertTrue(lines.get(nextLineCount++).startsWith("\tdisplayName: "), errmsg);
- assertTrue(lines.get(nextLineCount++).startsWith("\tidentity: "), errmsg);
- if (lines.get(nextLineCount).startsWith("\tendpoint: ")) nextLineCount++;
- if (lines.get(nextLineCount).startsWith("\tregion: ")) nextLineCount++;
-
- List<String> result = Lists.newArrayList();
- for (String line : lines.subList(nextLineCount, lines.size()-1)) {
- assertTrue(line.startsWith("\t"), errmsg);
- result.add(line.substring(1));
- }
- return result;
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74ee6aac/usage/cli/src/test/java/org/apache/brooklyn/cli/CliTest.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/test/java/org/apache/brooklyn/cli/CliTest.java b/usage/cli/src/test/java/org/apache/brooklyn/cli/CliTest.java
new file mode 100644
index 0000000..96e3e93
--- /dev/null
+++ b/usage/cli/src/test/java/org/apache/brooklyn/cli/CliTest.java
@@ -0,0 +1,605 @@
+/*
+ * 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.cli;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+import groovy.lang.GroovyClassLoader;
+import io.airlift.command.Cli;
+import io.airlift.command.Command;
+import io.airlift.command.ParseException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Pattern;
+
+import org.apache.brooklyn.cli.Main;
+import org.apache.brooklyn.cli.AbstractMain.BrooklynCommand;
+import org.apache.brooklyn.cli.AbstractMain.BrooklynCommandCollectingArgs;
+import org.apache.brooklyn.cli.AbstractMain.HelpCommand;
+import org.apache.brooklyn.cli.Main.AppShutdownHandler;
+import org.apache.brooklyn.cli.Main.GeneratePasswordCommand;
+import org.apache.brooklyn.cli.Main.LaunchCommand;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.AbstractApplication;
+import brooklyn.entity.basic.AbstractEntity;
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.StartableApplication;
+import brooklyn.entity.proxying.EntityProxy;
+import brooklyn.entity.proxying.ImplementedBy;
+import brooklyn.entity.trait.Startable;
+import brooklyn.location.Location;
+import brooklyn.location.basic.SimulatedLocation;
+import brooklyn.test.Asserts;
+import brooklyn.test.entity.LocalManagementContextForTests;
+import brooklyn.util.ResourceUtils;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.FatalConfigurationRuntimeException;
+import brooklyn.util.exceptions.UserFacingException;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.io.Files;
+
+public class CliTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CliTest.class);
+
+ // See testInvokeGroovyScript test for usage
+ public static final AtomicBoolean GROOVY_INVOKED = new AtomicBoolean(false);
+
+ private ExecutorService executor;
+ private StartableApplication app;
+ private static volatile ExampleEntity exampleEntity;
+
+ // static so that they can be set from the static classes ExampleApp and ExampleEntity
+ private static volatile boolean exampleAppRunning;
+ private static volatile boolean exampleAppConstructed;
+ private static volatile boolean exampleEntityRunning;
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() throws Exception {
+ executor = Executors.newCachedThreadPool();
+ exampleAppConstructed = false;
+ exampleAppRunning = false;
+ exampleEntityRunning = false;
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() throws Exception {
+ if (executor != null) executor.shutdownNow();
+ if (app != null) Entities.destroyAll(app.getManagementContext());
+ if (exampleEntity != null && exampleEntity.getApplication() != null) Entities.destroyAll(exampleEntity.getApplication().getManagementContext());
+ }
+
+ @Test
+ public void testLoadApplicationFromClasspath() throws Exception {
+ String appName = ExampleApp.class.getName();
+ Object appBuilder = loadApplicationFromClasspathOrParse(appName);
+ assertTrue(appBuilder instanceof ApplicationBuilder, "app="+appBuilder);
+ assertAppWrappedInBuilder((ApplicationBuilder)appBuilder, ExampleApp.class.getCanonicalName());
+ }
+
+ @Test
+ public void testLoadApplicationBuilderFromClasspath() throws Exception {
+ String appName = ExampleAppBuilder.class.getName();
+ Object appBuilder = loadApplicationFromClasspathOrParse(appName);
+ assertTrue(appBuilder instanceof ExampleAppBuilder, "app="+appBuilder);
+ }
+
+ @Test
+ public void testLoadEntityFromClasspath() throws Exception {
+ String entityName = ExampleEntity.class.getName();
+ Object appBuilder = loadApplicationFromClasspathOrParse(entityName);
+ assertTrue(appBuilder instanceof ApplicationBuilder, "app="+appBuilder);
+
+ app = ((ApplicationBuilder)appBuilder).manage();
+ Collection<Entity> entities = app.getChildren();
+ assertEquals(entities.size(), 1, "entities="+entities);
+ assertTrue(Iterables.getOnlyElement(entities) instanceof ExampleEntity, "entities="+entities+"; ifs="+Iterables.getOnlyElement(entities).getClass().getInterfaces());
+ assertTrue(Iterables.getOnlyElement(entities) instanceof EntityProxy, "entities="+entities);
+ }
+
+ @Deprecated // Tests deprecated approach of using impl directly
+ @Test
+ public void testLoadEntityImplFromClasspath() throws Exception {
+ String entityName = ExampleEntityImpl.class.getName();
+ Object appBuilder = loadApplicationFromClasspathOrParse(entityName);
+ assertTrue(appBuilder instanceof ApplicationBuilder, "app="+appBuilder);
+
+ app = ((ApplicationBuilder)appBuilder).manage();
+ Collection<Entity> entities = app.getChildren();
+ assertEquals(entities.size(), 1, "entities="+entities);
+ assertEquals(Iterables.getOnlyElement(entities).getEntityType().getName(), ExampleEntity.class.getCanonicalName(), "entities="+entities);
+ assertTrue(Iterables.getOnlyElement(entities) instanceof EntityProxy, "entities="+entities);
+ }
+
+ @Test
+ public void testLoadApplicationByParsingGroovyFile() throws Exception {
+ String appName = "ExampleAppInFile.groovy"; // file found in src/test/resources (contains empty app)
+ Object appBuilder = loadApplicationFromClasspathOrParse(appName);
+ assertTrue(appBuilder instanceof ApplicationBuilder, "app="+appBuilder);
+ assertAppWrappedInBuilder((ApplicationBuilder)appBuilder, "ExampleAppInFile");
+ }
+
+ private Object loadApplicationFromClasspathOrParse(String appName) throws Exception {
+ LaunchCommand launchCommand = new Main.LaunchCommand();
+ ResourceUtils resourceUtils = ResourceUtils.create(this);
+ GroovyClassLoader loader = new GroovyClassLoader(CliTest.class.getClassLoader());
+ return launchCommand.loadApplicationFromClasspathOrParse(resourceUtils, loader, appName);
+ }
+
+ private void assertAppWrappedInBuilder(ApplicationBuilder builder, String expectedAppTypeName) {
+ StartableApplication app = builder.manage();
+ try {
+ String typeName = app.getEntityType().getName();
+ assertEquals(typeName, expectedAppTypeName, "app="+app+"; typeName="+typeName);
+ } finally {
+ Entities.destroyAll(app.getManagementContext());
+ }
+ }
+
+ @Test
+ public void testInvokeGroovyScript() throws Exception {
+ File groovyFile = File.createTempFile("testinvokegroovy", "groovy");
+ try {
+ String contents = CliTest.class.getCanonicalName()+".GROOVY_INVOKED.set(true);";
+ Files.write(contents.getBytes(), groovyFile);
+
+ LaunchCommand launchCommand = new Main.LaunchCommand();
+ ResourceUtils resourceUtils = ResourceUtils.create(this);
+ GroovyClassLoader loader = new GroovyClassLoader(CliTest.class.getClassLoader());
+ launchCommand.execGroovyScript(resourceUtils, loader, groovyFile.toURI().toString());
+ assertTrue(GROOVY_INVOKED.get());
+
+ } finally {
+ groovyFile.delete();
+ GROOVY_INVOKED.set(false);
+ }
+ }
+
+ @Test
+ public void testStopAllApplications() throws Exception {
+ LaunchCommand launchCommand = new Main.LaunchCommand();
+ ExampleApp app = new ExampleApp();
+ try {
+ Entities.startManagement(app);
+ app.start(ImmutableList.of(new SimulatedLocation()));
+ assertTrue(app.running);
+
+ launchCommand.stopAllApps(ImmutableList.of(app));
+ assertFalse(app.running);
+ } finally {
+ Entities.destroyAll(app.getManagementContext());
+ }
+ }
+
+ @Test
+ public void testWaitsForInterrupt() throws Exception {
+ final AppShutdownHandler listener = new AppShutdownHandler();
+ Thread t = new Thread(new Runnable() {
+ @Override public void run() {
+ listener.waitOnShutdownRequest();
+ }});
+
+ t.start();
+ t.join(100);
+ assertTrue(t.isAlive());
+
+ t.interrupt();
+ t.join(10*1000);
+ assertFalse(t.isAlive());
+ }
+
+ protected Cli<BrooklynCommand> buildCli() {
+ return new Main().cliBuilder().build();
+ }
+
+ @Test
+ public void testLaunchCommandParsesArgs() throws ParseException {
+ BrooklynCommand command = buildCli().parse("launch",
+ "--app", "my.App",
+ "--location", "localhost",
+ "--port", "1234",
+ "--bindAddress", "myhostname",
+ "--noConsole", "--noConsoleSecurity", "--stopOnKeyPress",
+ "--localBrooklynProperties", "/path/to/myprops",
+ LaunchCommand.PERSIST_OPTION, LaunchCommand.PERSIST_OPTION_REBIND,
+ "--persistenceDir", "/path/to/mypersist",
+ LaunchCommand.HA_OPTION, LaunchCommand.HA_OPTION_STANDBY);
+ assertTrue(command instanceof LaunchCommand, ""+command);
+ String details = command.toString();
+ assertTrue(details.contains("app=my.App"), details);
+ assertTrue(details.contains("script=null"), details);
+ assertTrue(details.contains("location=localhost"), details);
+ assertTrue(details.contains("port=1234"), details);
+ assertTrue(details.contains("bindAddress=myhostname"), details);
+ assertTrue(details.contains("noConsole=true"), details);
+ assertTrue(details.contains("noConsoleSecurity=true"), details);
+ assertTrue(details.contains("stopOnKeyPress=true"), details);
+ assertTrue(details.contains("localBrooklynProperties=/path/to/myprops"), details);
+ assertTrue(details.contains("persist=rebind"), details);
+ assertTrue(details.contains("persistenceDir=/path/to/mypersist"), details);
+ assertTrue(details.contains("highAvailability=standby"), details);
+ }
+
+ @Test
+ public void testLaunchCommandUsesDefaults() throws ParseException {
+ BrooklynCommand command = buildCli().parse("launch");
+ assertTrue(command instanceof LaunchCommand, ""+command);
+ String details = command.toString();
+ assertTrue(details.contains("app=null"), details);
+ assertTrue(details.contains("script=null"), details);
+ assertTrue(details.contains("location=null"), details);
+ assertTrue(details.contains("port=null"), details);
+ assertTrue(details.contains("noConsole=false"), details);
+ assertTrue(details.contains("noConsoleSecurity=false"), details);
+ assertTrue(details.contains("stopWhichAppsOnShutdown=theseIfNotPersisted"), details);
+ assertTrue(details.contains("stopOnKeyPress=false"), details);
+ assertTrue(details.contains("localBrooklynProperties=null"), details);
+ assertTrue(details.contains("persist=disabled"), details);
+ assertTrue(details.contains("persistenceDir=null"), details);
+ assertTrue(details.contains("highAvailability=auto"), details);
+ }
+
+ @Test
+ public void testLaunchCommandComplainsWithInvalidArgs() {
+ Cli<BrooklynCommand> cli = buildCli();
+ try {
+ BrooklynCommand command = cli.parse("launch", "invalid");
+ command.call();
+ Assert.fail("Should have thrown exception; instead got "+command);
+ } catch (ParseException e) {
+ /* expected */
+ } catch (Exception e) {
+ throw Exceptions.propagate(e);
+ }
+ }
+
+ @Test
+ public void testAppOptionIsOptional() throws ParseException {
+ Cli<BrooklynCommand> cli = buildCli();
+ cli.parse("launch", "blah", "my.App");
+ }
+
+ public void testHelpCommand() {
+ Cli<BrooklynCommand> cli = buildCli();
+ BrooklynCommand command = cli.parse("help");
+ assertTrue(command instanceof HelpCommand);
+ command = cli.parse();
+ assertTrue(command instanceof HelpCommand);
+ }
+
+ @Test
+ public void testLaunchWillStartAppWhenGivenImpl() throws Exception {
+ Cli<BrooklynCommand> cli = buildCli();
+ BrooklynCommand command = cli.parse("launch", "--noConsole", "--app", ExampleApp.class.getName(), "--location", "localhost");
+ submitCommandAndAssertRunnableSucceeds(command, new Runnable() {
+ public void run() {
+ assertTrue(exampleAppConstructed);
+ assertTrue(exampleAppRunning);
+ }
+ });
+ }
+
+ @Test
+ public void testLaunchStartsYamlApp() throws Exception {
+ Cli<BrooklynCommand> cli = buildCli();
+ BrooklynCommand command = cli.parse("launch", "--noConsole", "--app", "example-app-no-location.yaml", "--location", "localhost");
+ submitCommandAndAssertRunnableSucceeds(command, new Runnable() {
+ public void run() {
+ assertTrue(exampleEntityRunning);
+ }
+ });
+ }
+
+ @Test
+ public void testLaunchStartsYamlAppWithCommandLineLocation() throws Exception {
+ Cli<BrooklynCommand> cli = buildCli();
+ BrooklynCommand command = cli.parse("launch", "--noConsole", "--app", "example-app-no-location.yaml", "--location", "localhost:(name=testLocalhost)");
+ submitCommandAndAssertRunnableSucceeds(command, new Runnable() {
+ public void run() {
+ assertTrue(exampleEntityRunning);
+ assertTrue(Iterables.getOnlyElement(exampleEntity.getApplication().getLocations()).getDisplayName().equals("testLocalhost"));
+ }
+ });
+ }
+
+ @Test
+ public void testLaunchStartsYamlAppWithYamlAppLocation() throws Exception {
+ Cli<BrooklynCommand> cli = buildCli();
+ BrooklynCommand command = cli.parse("launch", "--noConsole", "--app", "example-app-app-location.yaml");
+ submitCommandAndAssertRunnableSucceeds(command, new Runnable() {
+ public void run() {
+ assertTrue(exampleEntityRunning);
+ assertTrue(Iterables.getOnlyElement(exampleEntity.getApplication().getLocations()).getDisplayName().equals("appLocalhost"));
+ }
+ });
+ }
+
+ @Test
+ public void testLaunchStartsYamlAppWithYamlAndAppCliLocation() throws Exception {
+ Cli<BrooklynCommand> cli = buildCli();
+ BrooklynCommand command = cli.parse("launch", "--noConsole", "--app", "example-app-app-location.yaml", "--location", "localhost");
+ submitCommandAndAssertRunnableSucceeds(command, new Runnable() {
+ public void run() {
+ assertTrue(exampleEntityRunning);
+ assertTrue(Iterables.getFirst(exampleEntity.getApplication().getLocations(), null).getDisplayName().equals("appLocalhost"));
+ }
+ });
+ }
+
+ @Test
+ public void testGeneratePasswordCommandParsed() throws Exception {
+ Cli<BrooklynCommand> cli = buildCli();
+ BrooklynCommand command = cli.parse("generate-password", "--user", "myname");
+
+ assertTrue(command instanceof GeneratePasswordCommand);
+ }
+
+ @Test
+ public void testGeneratePasswordFromStdin() throws Exception {
+ List<String> stdoutLines = runCommand(ImmutableList.of("generate-password", "--user", "myname", "--stdin"), "mypassword\nmypassword\n");
+
+ System.out.println(stdoutLines);
+ }
+
+ @Test
+ public void testGeneratePasswordFailsIfPasswordsDontMatch() throws Throwable {
+ Throwable exception = runCommandExpectingException(ImmutableList.of("generate-password", "--user", "myname", "--stdin"), "mypassword\ndifferentpassword\n");
+ if (exception instanceof UserFacingException && exception.toString().contains("Passwords did not match")) {
+ // success
+ } else {
+ throw new Exception(exception);
+ }
+ }
+
+ @Test
+ public void testGeneratePasswordFailsIfNoConsole() throws Throwable {
+ Throwable exception = runCommandExpectingException(ImmutableList.of("generate-password", "--user", "myname"), "");
+ if (exception instanceof FatalConfigurationRuntimeException && exception.toString().contains("No console")) {
+ // success
+ } else {
+ throw new Exception(exception);
+ }
+ }
+
+ @Test
+ public void testGeneratePasswordFailsIfPasswordBlank() throws Throwable {
+ Throwable exception = runCommandExpectingException(ImmutableList.of("generate-password", "--user", "myname", "--stdin"), "\n\n");
+ if (exception instanceof UserFacingException && exception.toString().contains("Password must not be blank")) {
+ // success
+ } else {
+ throw new Exception(exception);
+ }
+ }
+
+ @Test
+ public void testInfoShowsDefaultBanner() throws Exception {
+ List<String> stdoutLines = runCommand(ImmutableList.of("info"), "");
+
+ for (String line : Splitter.on("\n").split(Main.DEFAULT_BANNER)) {
+ assertTrue(stdoutLines.contains(line), "out="+stdoutLines);
+ }
+ }
+
+ @Test
+ public void testInfoSupportsCustomizedBanner() throws Exception {
+ String origBanner = Main.banner;
+ String origBannerFirstLine = Iterables.get(Splitter.on("\n").split(Main.DEFAULT_BANNER), 0);
+ try {
+ String customBanner = "My Custom Banner";
+ Main.banner = customBanner;
+ List<String> stdoutLines = runCommand(ImmutableList.of("info"), "");
+
+ assertTrue(stdoutLines.contains(customBanner), "out="+stdoutLines);
+ assertFalse(stdoutLines.contains(origBannerFirstLine), "out="+stdoutLines);
+ } finally {
+ Main.banner = origBanner;
+ }
+ }
+
+ @Test
+ public void testCanCustomiseInfoCommand() throws Exception {
+ Main main = new Main() {
+ protected Class<? extends BrooklynCommand> cliInfoCommand() {
+ return CustomInfoCommand.class;
+ }
+ };
+ List<String> stdoutLines = runCommand(main.cliBuilder().build(), ImmutableList.of("info"), "");
+ assertTrue(stdoutLines.contains("My Custom Info"), "out="+stdoutLines);
+ }
+
+ @Command(name = "info", description = "Display information about brooklyn")
+ public static class CustomInfoCommand extends BrooklynCommandCollectingArgs {
+ @Override
+ public Void call() throws Exception {
+ System.out.println("My Custom Info");
+ return null;
+ }
+ }
+
+ @Test
+ public void testCanCustomiseLaunchCommand() throws Exception {
+ Main main = new Main() {
+ protected Class<? extends BrooklynCommand> cliLaunchCommand() {
+ return CustomLaunchCommand.class;
+ }
+ };
+ List<String> stdoutLines = runCommand(main.cliBuilder().build(), ImmutableList.of("launch"), "");
+ assertTrue(stdoutLines.contains("My Custom Launch"), "out="+stdoutLines);
+ }
+
+ @Command(name = "launch", description = "Starts a server, optionally with applications")
+ public static class CustomLaunchCommand extends BrooklynCommandCollectingArgs {
+ @Override
+ public Void call() throws Exception {
+ System.out.println("My Custom Launch");
+ return null;
+ }
+ }
+
+ protected Throwable runCommandExpectingException(Iterable<String> args, String input) throws Exception {
+ try {
+ List<String> stdout = runCommand(args, input);
+ fail("Expected exception, but got stdout="+stdout);
+ return null;
+ } catch (ExecutionException e) {
+ return e.getCause();
+ }
+ }
+
+ protected List<String> runCommand(Iterable<String> args, String input) throws Exception {
+ Cli<BrooklynCommand> cli = buildCli();
+ return runCommand(cli, args, input);
+ }
+
+ protected List<String> runCommand(Cli<BrooklynCommand> cli, Iterable<String> args, String input) throws Exception {
+ final BrooklynCommand command = cli.parse(args);
+
+ final AtomicReference<Exception> exception = new AtomicReference<Exception>();
+ Thread t= new Thread(new Runnable() {
+ public void run() {
+ try {
+ command.call();
+ } catch (Exception e) {
+ exception.set(e);
+ throw Exceptions.propagate(e);
+ }
+ }});
+
+ InputStream origIn = System.in;
+ PrintStream origOut = System.out;
+ try {
+ InputStream stdin = new ByteArrayInputStream(input.getBytes());
+ System.setIn(stdin);
+
+ ByteArrayOutputStream stdoutBytes = new ByteArrayOutputStream();
+ PrintStream stdout = new PrintStream(stdoutBytes);
+ System.setOut(stdout);
+
+ t.start();
+
+ t.join(10*1000);
+ assertFalse(t.isAlive());
+
+ if (exception.get() != null) {
+ throw new ExecutionException(exception.get());
+ }
+
+ return ImmutableList.copyOf(Splitter.on(Pattern.compile("\r?\n")).split(new String(stdoutBytes.toByteArray())));
+ } finally {
+ System.setIn(origIn);
+ System.setOut(origOut);
+ t.interrupt();
+ }
+ }
+
+ private void submitCommandAndAssertRunnableSucceeds(final BrooklynCommand command, Runnable runnable) {
+ if (command instanceof LaunchCommand) {
+ ((LaunchCommand)command).useManagementContext(new LocalManagementContextForTests());
+ }
+ executor.submit(new Callable<Void>() {
+ public Void call() throws Exception {
+ try {
+ LOG.info("Calling command: "+command);
+ command.call();
+ return null;
+ } catch (Throwable t) {
+ LOG.error("Error executing command: "+t, t);
+ throw Exceptions.propagate(t);
+ }
+ }});
+
+ Asserts.succeedsEventually(MutableMap.of("timeout", Duration.ONE_MINUTE), runnable);
+ }
+
+ // An empty app to be used for testing
+ public static class ExampleApp extends AbstractApplication {
+ volatile boolean running;
+ volatile boolean constructed;
+
+ @Override public void init() {
+ super.init();
+ constructed = true;
+ exampleAppConstructed = true;
+ }
+ @Override public void start(Collection<? extends Location> locations) {
+ super.start(locations);
+ running = true;
+ exampleAppRunning = true;
+ }
+ @Override public void stop() {
+ super.stop();
+ running = false;
+ exampleAppRunning = false;
+ }
+ }
+
+ // An empty entity to be used for testing
+ @ImplementedBy(ExampleEntityImpl.class)
+ public static interface ExampleEntity extends Entity, Startable {
+ }
+
+ public static class ExampleEntityImpl extends AbstractEntity implements ExampleEntity {
+ public ExampleEntityImpl() {
+ super();
+ exampleEntity = this;
+ }
+ @Override public void start(Collection<? extends Location> locations) {
+ exampleEntityRunning = true;
+ }
+ @Override public void stop() {
+ exampleEntityRunning = false;
+ }
+ @Override public void restart() {
+ }
+ }
+
+ // An empty app builder to be used for testing
+ public static class ExampleAppBuilder extends ApplicationBuilder {
+ @Override protected void doBuild() {
+ // no-op
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74ee6aac/usage/cli/src/test/java/org/apache/brooklyn/cli/CloudExplorerLiveTest.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/test/java/org/apache/brooklyn/cli/CloudExplorerLiveTest.java b/usage/cli/src/test/java/org/apache/brooklyn/cli/CloudExplorerLiveTest.java
new file mode 100644
index 0000000..8abe1c0
--- /dev/null
+++ b/usage/cli/src/test/java/org/apache/brooklyn/cli/CloudExplorerLiveTest.java
@@ -0,0 +1,209 @@
+/*
+ * 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.cli;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import io.airlift.command.Cli;
+import io.airlift.command.ParseException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.List;
+
+import org.apache.brooklyn.cli.Main;
+import org.apache.brooklyn.cli.AbstractMain.BrooklynCommand;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+public class CloudExplorerLiveTest {
+
+ private String stdout;
+ private String stderr;
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() {
+ stdout = null;
+ stderr = null;
+ }
+
+ @Test
+ public void testNoArgsThrows() throws Exception {
+ try {
+ call(new String[0]);
+ Assert.fail("No args should fail");
+ } catch (ParseException e) {
+ Assert.assertTrue(e.toString().contains("No command specified"), ""+e);
+ }
+ }
+
+ // A user running these tests might not have any instances; so don't assert that there will be one
+ @Test(groups={"Live", "Live-sanity"})
+ public void testListInstances() throws Exception {
+ call("cloud-compute", "list-instances", "--location", "jclouds:aws-ec2:eu-west-1");
+
+ String errmsg = "stdout="+stdout+"; stderr="+stderr;
+
+ List<String> lines = assertAndStipSingleLocationHeader(stdout);
+ assertTrue(lines.get(0).equals("Instances {"), errmsg);
+ assertTrue(lines.get(lines.size()-1).equals("}"), errmsg);
+ assertTrue(stderr.isEmpty(), errmsg);
+ }
+
+ @Test(groups={"Live", "Live-sanity"})
+ public void testListImages() throws Exception {
+ call("cloud-compute", "list-images", "--location", "jclouds:softlayer:ams01");
+
+ String errmsg = "stdout="+stdout+"; stderr="+stderr;
+
+ // FIXME Now has location details pre-amble; fix assertions
+ List<String> lines = assertAndStipSingleLocationHeader(stdout);
+ assertTrue(lines.get(0).equals("Images {"), errmsg);
+ assertTrue(lines.get(lines.size()-1).equals("}"), errmsg);
+ assertTrue(stderr.isEmpty(), errmsg);
+
+ List<String> imageLines = lines.subList(1, lines.size()-1);
+ assertTrue(imageLines.size() > 0, errmsg);
+ assertTrue(imageLines.get(0).matches(".*id=.*providerId=.*os=.*description=.*"), "line="+imageLines.get(0)+"; "+errmsg);
+ }
+
+ @Test(groups={"Live", "Live-sanity"})
+ public void testListHardwareProfiles() throws Exception {
+ call("cloud-compute", "list-hardware-profiles", "--location", "jclouds:softlayer:ams01");
+
+ String errmsg = "stdout="+stdout+"; stderr="+stderr;
+
+ // FIXME Now has location details pre-amble; fix assertions
+ List<String> lines = assertAndStipSingleLocationHeader(stdout);
+ assertTrue(lines.get(0).equals("Hardware Profiles {"), errmsg);
+ assertTrue(lines.get(lines.size()-1).equals("}"), errmsg);
+ assertTrue(stderr.isEmpty(), errmsg);
+
+ List<String> hardwareProfileLines = lines.subList(1, lines.size()-1);
+ assertTrue(hardwareProfileLines.size() > 0, errmsg);
+ assertTrue(hardwareProfileLines.get(0).matches(".*cpu=.*memory=.*processors=.*"), "line="+hardwareProfileLines.get(0)+"; "+errmsg);
+ }
+
+ @Test(groups={"Live", "Live-sanity"})
+ public void testGetImage() throws Exception {
+ call("cloud-compute", "get-image", "--location", "jclouds:softlayer:ams01", "CENTOS_6_64");
+
+ String errmsg = "stdout="+stdout+"; stderr="+stderr;
+
+ // FIXME Now has location details pre-amble; fix assertions
+ List<String> lines = assertAndStipSingleLocationHeader(stdout);
+ assertTrue(lines.get(0).equals("Image CENTOS_6_64 {"), errmsg);
+ assertTrue(lines.get(lines.size()-1).equals("}"), errmsg);
+ assertTrue(stderr.isEmpty(), errmsg);
+
+ List<String> imageLines = lines.subList(1, lines.size()-1);
+ assertTrue(imageLines.size() > 0, errmsg);
+ assertTrue(imageLines.get(0).matches(".*id=.*providerId=.*os=.*description=.*"), "line="+imageLines.get(0)+"; "+errmsg);
+ }
+
+ @Test(groups={"Live", "Live-sanity"})
+ public void testGetDefaultTemplate() throws Exception {
+ call("cloud-compute", "default-template", "--location", "jclouds:softlayer:ams01");
+
+ String errmsg = "stdout="+stdout+"; stderr="+stderr;
+
+ // FIXME Now has location details pre-amble; fix assertions
+ List<String> lines = assertAndStipSingleLocationHeader(stdout);
+ assertTrue(lines.get(0).equals("Default template {"), errmsg);
+ assertTrue(lines.get(lines.size()-1).equals("}"), errmsg);
+ assertTrue(stderr.isEmpty(), errmsg);
+
+ List<String> imageLines = lines.subList(1, lines.size()-1);
+ assertTrue(imageLines.size() > 0, errmsg);
+ assertTrue(imageLines.get(0).matches("\tImage.*id=.*providerId=.*os=.*description=.*"), "line="+imageLines.get(0)+"; "+errmsg);
+ assertTrue(imageLines.get(1).matches("\tHardware.*cpu=.*memory=.*processors=.*"), "line="+imageLines.get(1)+"; "+errmsg);
+ assertTrue(imageLines.get(2).matches("\tLocation.*scope=.*"), "line="+imageLines.get(2)+"; "+errmsg);
+ assertTrue(imageLines.get(3).matches("\tOptions.*"), "line="+imageLines.get(3)+"; "+errmsg);
+ }
+
+ /**
+ * Expects in brooklyn.properties:
+ * brooklyn.location.named.softlayer-swift-ams01=jclouds:swift:https://ams01.objectstorage.softlayer.net/auth/v1.0
+ * brooklyn.location.named.softlayer-swift-ams01.identity=ABCDEFGH:myusername
+ * brooklyn.location.named.softlayer-swift-ams01.credential=1234567890...
+ */
+ @Test(groups={"Live", "Live-sanity"})
+ public void testListContainers() throws Exception {
+ call("cloud-blobstore", "list-containers", "--location", "named:softlayer-swift-ams01");
+
+ String errmsg = "stdout="+stdout+"; stderr="+stderr;
+
+ // FIXME Now has location details pre-amble; fix assertions
+ List<String> lines = assertAndStipSingleLocationHeader(stdout);
+ assertTrue(lines.get(0).equals("Containers {"), errmsg);
+ assertTrue(lines.get(lines.size()-1).equals("}"), errmsg);
+ assertTrue(stderr.isEmpty(), errmsg);
+ }
+
+ protected void call(String... args) throws Exception {
+ call(new ByteArrayInputStream(new byte[0]), args);
+ }
+
+ protected void call(InputStream instream, String... args) throws Exception {
+ ByteArrayOutputStream stdoutStream = new ByteArrayOutputStream();
+ ByteArrayOutputStream stderrStream = new ByteArrayOutputStream();
+
+ Cli<BrooklynCommand> parser = new Main().cliBuilder().build();
+
+ BrooklynCommand command = parser.parse(args);
+ command.stdout = new PrintStream(stdoutStream);
+ command.stderr = new PrintStream(stderrStream);
+ command.stdin = instream;
+ try {
+ command.call();
+ } finally {
+ stdout = new String(stdoutStream.toByteArray());
+ stderr = new String(stderrStream.toByteArray());
+ }
+ }
+
+ private List<String> assertAndStipSingleLocationHeader(String stdout) {
+ List<String> lines = ImmutableList.copyOf(Splitter.on("\n").omitEmptyStrings().split(stdout));
+
+ String errmsg = "lines="+lines;
+
+ int nextLineCount = 0;
+ assertEquals(lines.get(nextLineCount++), "Location {", errmsg);
+ assertEquals(lines.get(lines.size()-1), "}", errmsg);
+ assertTrue(lines.get(nextLineCount++).startsWith("\tprovider: "), errmsg);
+ assertTrue(lines.get(nextLineCount++).startsWith("\tdisplayName: "), errmsg);
+ assertTrue(lines.get(nextLineCount++).startsWith("\tidentity: "), errmsg);
+ if (lines.get(nextLineCount).startsWith("\tendpoint: ")) nextLineCount++;
+ if (lines.get(nextLineCount).startsWith("\tregion: ")) nextLineCount++;
+
+ List<String> result = Lists.newArrayList();
+ for (String line : lines.subList(nextLineCount, lines.size()-1)) {
+ assertTrue(line.startsWith("\t"), errmsg);
+ result.add(line.substring(1));
+ }
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74ee6aac/usage/cli/src/test/resources/example-app-app-location.yaml
----------------------------------------------------------------------
diff --git a/usage/cli/src/test/resources/example-app-app-location.yaml b/usage/cli/src/test/resources/example-app-app-location.yaml
index aca5362..f161e8d 100644
--- a/usage/cli/src/test/resources/example-app-app-location.yaml
+++ b/usage/cli/src/test/resources/example-app-app-location.yaml
@@ -19,5 +19,5 @@
name: example-app-app-location
location: localhost:(name=appLocalhost)
services:
-- serviceType: brooklyn.cli.CliTest$ExampleEntity
+- serviceType: org.apache.brooklyn.cli.CliTest$ExampleEntity
name: Example app
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74ee6aac/usage/cli/src/test/resources/example-app-entity-location.yaml
----------------------------------------------------------------------
diff --git a/usage/cli/src/test/resources/example-app-entity-location.yaml b/usage/cli/src/test/resources/example-app-entity-location.yaml
index cbca856..5b2e466 100644
--- a/usage/cli/src/test/resources/example-app-entity-location.yaml
+++ b/usage/cli/src/test/resources/example-app-entity-location.yaml
@@ -18,6 +18,6 @@
#
name: example-app-entity-location
services:
-- serviceType: brooklyn.cli.CliTest$ExampleEntity
+- serviceType: org.apache.brooklyn.cli.CliTest$ExampleEntity
name: Example app
location: localhost:(name=entityLocalhost)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74ee6aac/usage/cli/src/test/resources/example-app-no-location.yaml
----------------------------------------------------------------------
diff --git a/usage/cli/src/test/resources/example-app-no-location.yaml b/usage/cli/src/test/resources/example-app-no-location.yaml
index 9592e61..60cff1c 100644
--- a/usage/cli/src/test/resources/example-app-no-location.yaml
+++ b/usage/cli/src/test/resources/example-app-no-location.yaml
@@ -18,5 +18,5 @@
#
name: example-app-no-location
services:
-- serviceType: brooklyn.cli.CliTest$ExampleEntity
+- serviceType: org.apache.brooklyn.cli.CliTest$ExampleEntity
name: Example app