http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9e5ca55/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncher.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncher.java
 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncher.java
new file mode 100644
index 0000000..5fc2670
--- /dev/null
+++ 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncher.java
@@ -0,0 +1,433 @@
+/*
+ * 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.rest;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.EnumSet;
+import java.util.List;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+
+import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherAbstract;
+import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.reflections.util.ClasspathHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.config.BrooklynServerConfig;
+import brooklyn.config.BrooklynServiceAttributes;
+import brooklyn.management.ManagementContext;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.rest.filter.BrooklynPropertiesSecurityFilter;
+import org.apache.brooklyn.rest.filter.HaMasterCheckFilter;
+import org.apache.brooklyn.rest.filter.LoggingFilter;
+import org.apache.brooklyn.rest.filter.NoCacheFilter;
+import org.apache.brooklyn.rest.filter.RequestTaggingFilter;
+import org.apache.brooklyn.rest.security.provider.AnyoneSecurityProvider;
+import org.apache.brooklyn.rest.security.provider.SecurityProvider;
+import org.apache.brooklyn.rest.util.ManagementContextProvider;
+import org.apache.brooklyn.rest.util.ShutdownHandlerProvider;
+import org.apache.brooklyn.rest.util.TestShutdownHandler;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.net.Networking;
+import brooklyn.util.text.WildcardGlobs;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+import com.sun.jersey.api.core.DefaultResourceConfig;
+import com.sun.jersey.api.core.ResourceConfig;
+import com.sun.jersey.spi.container.servlet.ServletContainer;
+
+/** Convenience and demo for launching programmatically. Also used for 
automated tests.
+ * <p>
+ * BrooklynLauncher has a more full-featured CLI way to start, 
+ * but if you want more control you can:
+ * <li> take the WAR this project builds (REST API) -- NB probably want the 
unshaded one (containing all deps)
+ * <li> take the WAR from the jsgui project _and_ this WAR and combine them 
+ *      (this one should run as a filter on the others, _not_ as a 
ResourceCollection where they fight over who's got root)
+ * <li> programmatically install things, following the examples herein; 
+ *      in particular {@link #installAsServletFilter(ServletContextHandler)} 
is quite handy! 
+ * <p>
+ * You can also just run this class. In most installs it just works, assuming 
your IDE or maven-fu gives you the classpath.
+ * Add more apps and entities on the classpath and they'll show up in the 
catalog.
+ **/
+public class BrooklynRestApiLauncher {
+
+    private static final Logger log = 
LoggerFactory.getLogger(BrooklynRestApiLauncher.class);
+    final static int FAVOURITE_PORT = 8081;
+    public static final String SCANNING_CATALOG_BOM_URL = 
"classpath://brooklyn/scanning.catalog.bom";
+
+    enum StartMode {
+        FILTER, SERVLET, WEB_XML
+    }
+
+    public static final List<Class<? extends Filter>> DEFAULT_FILTERS = 
ImmutableList.of(
+            RequestTaggingFilter.class,
+            BrooklynPropertiesSecurityFilter.class,
+            LoggingFilter.class,
+            HaMasterCheckFilter.class);
+
+    private boolean forceUseOfDefaultCatalogWithJavaClassPath = false;
+    private Class<? extends SecurityProvider> securityProvider;
+    private List<Class<? extends Filter>> filters = DEFAULT_FILTERS;
+    private StartMode mode = StartMode.FILTER;
+    private ManagementContext mgmt;
+    private ContextHandler customContext;
+    private boolean deployJsgui = true;
+    private boolean disableHighAvailability = true;
+    private final TestShutdownHandler shutdownListener = new 
TestShutdownHandler();
+
+    protected BrooklynRestApiLauncher() {}
+
+    public BrooklynRestApiLauncher managementContext(ManagementContext mgmt) {
+        this.mgmt = mgmt;
+        return this;
+    }
+
+    public BrooklynRestApiLauncher 
forceUseOfDefaultCatalogWithJavaClassPath(boolean 
forceUseOfDefaultCatalogWithJavaClassPath) {
+        this.forceUseOfDefaultCatalogWithJavaClassPath = 
forceUseOfDefaultCatalogWithJavaClassPath;
+        return this;
+    }
+
+    public BrooklynRestApiLauncher securityProvider(Class<? extends 
SecurityProvider> securityProvider) {
+        this.securityProvider = securityProvider;
+        return this;
+    }
+
+    /**
+     * Runs the server with the given set of filters. 
+     * Overrides any previously supplied set (or {@link #DEFAULT_FILTERS} 
which is used by default).
+     */
+    public BrooklynRestApiLauncher filters(Class<? extends Filter>... filters) 
{
+        this.filters = Lists.newArrayList(filters);
+        return this;
+    }
+
+    public BrooklynRestApiLauncher mode(StartMode mode) {
+        this.mode = checkNotNull(mode, "mode");
+        return this;
+    }
+
+    /** Overrides start mode to use an explicit context */
+    public BrooklynRestApiLauncher customContext(ContextHandler customContext) 
{
+        this.customContext = checkNotNull(customContext, "customContext");
+        return this;
+    }
+
+    public BrooklynRestApiLauncher withJsgui() {
+        this.deployJsgui = true;
+        return this;
+    }
+
+    public BrooklynRestApiLauncher withoutJsgui() {
+        this.deployJsgui = false;
+        return this;
+    }
+
+    public BrooklynRestApiLauncher disableHighAvailability(boolean value) {
+        this.disableHighAvailability = value;
+        return this;
+    }
+
+    public Server start() {
+        if (this.mgmt == null) {
+            mgmt = new LocalManagementContext();
+        }
+        BrooklynCampPlatformLauncherAbstract platform = new 
BrooklynCampPlatformLauncherNoServer()
+                .useManagementContext(mgmt)
+                .launch();
+        ((LocalManagementContext)mgmt).noteStartupComplete();
+        log.debug("started "+platform);
+
+        ContextHandler context;
+        String summary;
+        if (customContext == null) {
+            switch (mode) {
+            case SERVLET:
+                context = servletContextHandler(mgmt);
+                summary = "programmatic Jersey ServletContainer servlet";
+                break;
+            case WEB_XML:
+                context = webXmlContextHandler(mgmt);
+                summary = "from WAR at " + ((WebAppContext) context).getWar();
+                break;
+            case FILTER:
+            default:
+                context = filterContextHandler(mgmt);
+                summary = "programmatic Jersey ServletContainer filter on 
webapp at " + ((WebAppContext) context).getWar();
+                break;
+            }
+        } else {
+            context = customContext;
+            summary = (context instanceof WebAppContext)
+                    ? "from WAR at " + ((WebAppContext) context).getWar()
+                    : "from custom context";
+        }
+
+        if (securityProvider != null) {
+            ((BrooklynProperties) mgmt.getConfig()).put(
+                    BrooklynWebConfig.SECURITY_PROVIDER_CLASSNAME, 
securityProvider.getName());
+        }
+
+        if (forceUseOfDefaultCatalogWithJavaClassPath) {
+            // sets URLs for a surefire
+            ((BrooklynProperties) 
mgmt.getConfig()).put(BrooklynServerConfig.BROOKLYN_CATALOG_URL, 
SCANNING_CATALOG_BOM_URL);
+            ((LocalManagementContext) 
mgmt).setBaseClassPathForScanning(ClasspathHelper.forJavaClassPath());
+        } else {
+            // don't use any catalog.xml which is set
+            ((BrooklynProperties) 
mgmt.getConfig()).put(BrooklynServerConfig.BROOKLYN_CATALOG_URL, 
ManagementContextInternal.EMPTY_CATALOG_URL);
+        }
+
+        return startServer(mgmt, context, summary, disableHighAvailability);
+    }
+
+    private ContextHandler filterContextHandler(ManagementContext mgmt) {
+        WebAppContext context = new WebAppContext();
+        
context.setAttribute(BrooklynServiceAttributes.BROOKLYN_MANAGEMENT_CONTEXT, 
mgmt);
+        context.setContextPath("/");
+        // here we run with the JS GUI, for convenience, if we can find it, 
else set up an empty dir
+        // TODO pretty sure there is an option to monitor this dir and load 
changes to static content
+        // NOTE: When running Brooklyn from an IDE (i.e. by launching 
BrooklynJavascriptGuiLauncher.main())
+        // you will need to ensure that the working directory is set to the 
jsgui folder. For IntelliJ,
+        // set the 'Working directory' of the Run/Debug Configuration to 
$MODULE_DIR/../jsgui.
+        // For Eclipse, use the default option of 
${workspace_loc:brooklyn-jsgui}.
+        // If the working directory is not set correctly, Brooklyn will be 
unable to find the jsgui .war
+        // file and the 'gui not available' message will be shown.
+        context.setWar(this.deployJsgui && findJsguiWebapp() != null
+                       ? findJsguiWebapp()
+                       : createTempWebDirWithIndexHtml("Brooklyn REST API <p> 
(gui not available)"));
+        installAsServletFilter(context, this.filters);
+        return context;
+    }
+
+    private ContextHandler servletContextHandler(ManagementContext 
managementContext) {
+        ResourceConfig config = new DefaultResourceConfig();
+        for (Object r: BrooklynRestApi.getAllResources())
+            config.getSingletons().add(r);
+        config.getSingletons().add(new 
ShutdownHandlerProvider(shutdownListener));
+
+        ServletContextHandler context = new 
ServletContextHandler(ServletContextHandler.SESSIONS);
+        
context.setAttribute(BrooklynServiceAttributes.BROOKLYN_MANAGEMENT_CONTEXT, 
managementContext);
+        ServletHolder servletHolder = new ServletHolder(new 
ServletContainer(config));
+        context.addServlet(servletHolder, "/*");
+        context.setContextPath("/");
+
+        installBrooklynFilters(context, this.filters);
+        return context;
+    }
+
+    private ContextHandler webXmlContextHandler(ManagementContext mgmt) {
+        // TODO add security to web.xml
+        WebAppContext context;
+        if (findMatchingFile("src/main/webapp")!=null) {
+            // running in source mode; need to use special classpath
+            context = new WebAppContext("src/main/webapp", "/");
+            context.setExtraClasspath("./target/classes");
+        } else if (findRestApiWar()!=null) {
+            context = new WebAppContext(findRestApiWar(), "/");
+        } else {
+            throw new IllegalStateException("Cannot find WAR for REST API. 
Expected in target/*.war, Maven repo, or in source directories.");
+        }
+        
context.setAttribute(BrooklynServiceAttributes.BROOKLYN_MANAGEMENT_CONTEXT, 
mgmt);
+
+        return context;
+    }
+
+    /** starts a server, on all NICs if security is configured,
+     * otherwise (no security) only on loopback interface */
+    public static Server startServer(ManagementContext mgmt, ContextHandler 
context, String summary, boolean disableHighAvailability) {
+        // TODO this repeats code in BrooklynLauncher / WebServer. should 
merge the two paths.
+        boolean secure = mgmt != null && 
!BrooklynWebConfig.hasNoSecurityOptions(mgmt.getConfig());
+        if (secure) {
+            log.debug("Detected security configured, launching server on all 
network interfaces");
+        } else {
+            log.debug("Detected no security configured, launching server on 
loopback (localhost) network interface only");
+            if (mgmt!=null) {
+                log.debug("Detected no security configured, running on 
loopback; disabling authentication");
+                
((BrooklynProperties)mgmt.getConfig()).put(BrooklynWebConfig.SECURITY_PROVIDER_CLASSNAME,
 AnyoneSecurityProvider.class.getName());
+            }
+        }
+        if (mgmt != null && disableHighAvailability)
+            mgmt.getHighAvailabilityManager().disabled();
+        InetSocketAddress bindLocation = new InetSocketAddress(
+                secure ? Networking.ANY_NIC : Networking.LOOPBACK,
+                        Networking.nextAvailablePort(FAVOURITE_PORT));
+        return startServer(context, summary, bindLocation);
+    }
+
+    public static Server startServer(ContextHandler context, String summary, 
InetSocketAddress bindLocation) {
+        Server server = new Server(bindLocation);
+        server.setHandler(context);
+        try {
+            server.start();
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+        log.info("Brooklyn REST server started ("+summary+") on");
+        log.info("  
http://localhost:"+server.getConnectors()[0].getLocalPort()+"/");
+
+        return server;
+    }
+
+    public static BrooklynRestApiLauncher launcher() {
+        return new BrooklynRestApiLauncher();
+    }
+
+    public static void main(String[] args) throws Exception {
+        startRestResourcesViaFilter();
+        log.info("Press Ctrl-C to quit.");
+    }
+
+    public static Server startRestResourcesViaFilter() {
+        return new BrooklynRestApiLauncher()
+                .mode(StartMode.FILTER)
+                .start();
+    }
+
+    public static Server startRestResourcesViaServlet() throws Exception {
+        return new BrooklynRestApiLauncher()
+                .mode(StartMode.SERVLET)
+                .start();
+    }
+
+    public static Server startRestResourcesViaWebXml() throws Exception {
+        return new BrooklynRestApiLauncher()
+                .mode(StartMode.WEB_XML)
+                .start();
+    }
+
+    public void installAsServletFilter(ServletContextHandler context) {
+        installAsServletFilter(context, DEFAULT_FILTERS);
+    }
+
+    private void installAsServletFilter(ServletContextHandler context, 
List<Class<? extends Filter>> filters) {
+        installBrooklynFilters(context, filters);
+
+        // now set up the REST servlet resources
+        ResourceConfig config = new DefaultResourceConfig();
+        // load all our REST API modules, JSON, and Swagger
+        for (Object r: BrooklynRestApi.getAllResources())
+            config.getSingletons().add(r);
+
+        // disable caching for dynamic content
+        
config.getProperties().put(ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS, 
NoCacheFilter.class.getName());
+        // Checks if appropriate request given HA status
+        
config.getProperties().put(ResourceConfig.PROPERTY_RESOURCE_FILTER_FACTORIES, 
org.apache.brooklyn.rest.filter.HaHotCheckResourceFilter.class.getName());
+        // configure to match empty path, or any thing which looks like a file 
path with /assets/ and extension html, css, js, or png
+        // and treat that as static content
+        
config.getProperties().put(ServletContainer.PROPERTY_WEB_PAGE_CONTENT_REGEX, 
"(/?|[^?]*/assets/[^?]+\\.[A-Za-z0-9_]+)");
+        // and anything which is not matched as a servlet also falls through 
(but more expensive than a regex check?)
+        
config.getFeatures().put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, true);
+        // finally create this as a _filter_ which falls through to a web app 
or something (optionally)
+        FilterHolder filterHolder = new FilterHolder(new 
ServletContainer(config));
+        context.addFilter(filterHolder, "/*", 
EnumSet.allOf(DispatcherType.class));
+
+        ManagementContext mgmt = (ManagementContext) 
context.getAttribute(BrooklynServiceAttributes.BROOKLYN_MANAGEMENT_CONTEXT);
+        config.getSingletons().add(new ManagementContextProvider(mgmt));
+        config.getSingletons().add(new 
ShutdownHandlerProvider(shutdownListener));
+    }
+
+    private static void installBrooklynFilters(ServletContextHandler context, 
List<Class<? extends Filter>> filters) {
+        for (Class<? extends Filter> filter : filters) {
+            context.addFilter(filter, "/*", 
EnumSet.allOf(DispatcherType.class));
+        }
+    }
+
+    /**
+     * Starts the server on all nics (even if security not enabled).
+     * @deprecated since 0.6.0; use {@link #launcher()} and set a custom 
context
+     */
+    @Deprecated
+    public static Server startServer(ContextHandler context, String summary) {
+        return BrooklynRestApiLauncher.startServer(context, summary,
+                new InetSocketAddress(Networking.ANY_NIC, 
Networking.nextAvailablePort(FAVOURITE_PORT)));
+    }
+
+    /** look for the JS GUI webapp in common places, returning path to it if 
found, or null */
+    private static String findJsguiWebapp() {
+        // could also look in maven repo ?
+        return Optional
+                .fromNullable(findMatchingFile("../jsgui/src/main/webapp"))
+                .or(findMatchingFile("../jsgui/target/*.war"))
+                .orNull();
+    }
+
+    /** look for the REST WAR file in common places, returning path to it if 
found, or null */
+    private static String findRestApiWar() {
+        // don't look at src/main/webapp here -- because classes won't be 
there!
+        // could also look in maven repo ?
+        return findMatchingFile("../rest/target/*.war").orNull();
+    }
+
+    /** returns the supplied filename if it exists (absolute or relative to 
the current directory);
+     * supports globs in the filename portion only, in which case it returns 
the _newest_ matching file.
+     * <p>
+     * otherwise returns null */
+    @Beta // public because used in dependent test projects
+    public static Optional<String> findMatchingFile(String filename) {
+        final File f = new File(filename);
+        if (f.exists()) return Optional.of(filename);
+        File dir = f.getParentFile();
+        File result = null;
+        if (dir.exists()) {
+            File[] matchingFiles = dir.listFiles(new FilenameFilter() {
+                @Override
+                public boolean accept(File dir, String name) {
+                    return WildcardGlobs.isGlobMatched(f.getName(), name);
+                }
+            });
+            for (File mf: matchingFiles) {
+                if (result==null || mf.lastModified() > result.lastModified()) 
result = mf;
+            }
+        }
+        if (result==null) return Optional.absent();
+        return Optional.of(result.getAbsolutePath());
+    }
+
+    /** create a directory with a simple index.html so we have some content 
being served up */
+    private static String createTempWebDirWithIndexHtml(String 
indexHtmlContent) {
+        File dir = Files.createTempDir();
+        dir.deleteOnExit();
+        try {
+            Files.write(indexHtmlContent, new File(dir, "index.html"), 
Charsets.UTF_8);
+        } catch (IOException e) {
+            Exceptions.propagate(e);
+        }
+        return dir.getAbsolutePath();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9e5ca55/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncherTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncherTest.java
 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncherTest.java
new file mode 100644
index 0000000..34ea94d
--- /dev/null
+++ 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncherTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.rest;
+
+import static 
org.apache.brooklyn.rest.BrooklynRestApiLauncher.StartMode.FILTER;
+import static 
org.apache.brooklyn.rest.BrooklynRestApiLauncher.StartMode.SERVLET;
+import static 
org.apache.brooklyn.rest.BrooklynRestApiLauncher.StartMode.WEB_XML;
+
+import java.util.concurrent.Callable;
+
+import org.apache.http.HttpStatus;
+import org.eclipse.jetty.server.Server;
+import org.testng.annotations.Test;
+
+import org.apache.brooklyn.rest.security.provider.AnyoneSecurityProvider;
+import 
org.apache.brooklyn.rest.util.BrooklynRestResourceUtilsTest.SampleNoOpApplication;
+import brooklyn.test.Asserts;
+import brooklyn.test.HttpTestUtils;
+
+public class BrooklynRestApiLauncherTest extends 
BrooklynRestApiLauncherTestFixture {
+
+    @Test
+    public void testFilterStart() throws Exception {
+        
checkRestCatalogApplications(useServerForTest(baseLauncher().mode(FILTER).start()));
+    }
+
+    @Test
+    public void testServletStart() throws Exception {
+        
checkRestCatalogApplications(useServerForTest(baseLauncher().mode(SERVLET).start()));
+    }
+
+    @Test
+    public void testWebAppStart() throws Exception {
+        
checkRestCatalogApplications(useServerForTest(baseLauncher().mode(WEB_XML).start()));
+    }
+
+    private BrooklynRestApiLauncher baseLauncher() {
+        return BrooklynRestApiLauncher.launcher()
+                .securityProvider(AnyoneSecurityProvider.class)
+                .forceUseOfDefaultCatalogWithJavaClassPath(true);
+    }
+    
+    private static void checkRestCatalogApplications(Server server) throws 
Exception {
+        final String rootUrl = 
"http://localhost:"+server.getConnectors()[0].getLocalPort();
+        int code = Asserts.succeedsEventually(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                int code = 
HttpTestUtils.getHttpStatusCode(rootUrl+"/v1/catalog/applications");
+                if (code == HttpStatus.SC_FORBIDDEN) {
+                    throw new RuntimeException("Retry request");
+                } else {
+                    return code;
+                }
+            }
+        });
+        HttpTestUtils.assertHealthyStatusCode(code);
+        
HttpTestUtils.assertContentContainsText(rootUrl+"/v1/catalog/applications", 
SampleNoOpApplication.class.getSimpleName());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9e5ca55/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncherTestFixture.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncherTestFixture.java
 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncherTestFixture.java
new file mode 100644
index 0000000..5f2f0c6
--- /dev/null
+++ 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncherTestFixture.java
@@ -0,0 +1,110 @@
+/*
+ * 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.rest;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.reflections.util.ClasspathHelper;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.config.BrooklynServerConfig;
+import brooklyn.config.BrooklynServiceAttributes;
+import brooklyn.entity.basic.Entities;
+import brooklyn.management.ManagementContext;
+import brooklyn.management.internal.LocalManagementContext;
+import org.apache.brooklyn.rest.security.provider.AnyoneSecurityProvider;
+import brooklyn.util.exceptions.Exceptions;
+
+public abstract class BrooklynRestApiLauncherTestFixture {
+
+    Server server = null;
+    
+    @AfterMethod(alwaysRun=true)
+    public void stopServer() throws Exception {
+        if (server!=null) {
+            ManagementContext mgmt = 
getManagementContextFromJettyServerAttributes(server);
+            server.stop();
+            if (mgmt!=null) Entities.destroyAll(mgmt);
+            server = null;
+        }
+    }
+    
+    protected Server newServer() {
+        try {
+            Server server = BrooklynRestApiLauncher.launcher()
+                    .forceUseOfDefaultCatalogWithJavaClassPath(true)
+                    .securityProvider(AnyoneSecurityProvider.class)
+                    .start();
+            return server;
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    protected Server useServerForTest(Server server) {
+        if (this.server!=null) {
+            Assert.fail("Test only meant for single server; already have 
"+this.server+" when checking "+server);
+        } else {
+            this.server = server;
+        }
+        return server;
+    }
+    
+    protected String getBaseUri() {
+        return getBaseUri(server);
+    }
+    public static String getBaseUri(Server server) {
+        return "http://localhost:"+server.getConnectors()[0].getLocalPort();
+    }
+    
+    public static void forceUseOfDefaultCatalogWithJavaClassPath(Server 
server) {
+        ManagementContext mgmt = 
getManagementContextFromJettyServerAttributes(server);
+        forceUseOfDefaultCatalogWithJavaClassPath(mgmt);
+    }
+
+    public static void 
forceUseOfDefaultCatalogWithJavaClassPath(ManagementContext manager) {
+        // TODO duplication with BrooklynRestApiLauncher ?
+        
+        // don't use any catalog.xml which is set
+        
((BrooklynProperties)manager.getConfig()).put(BrooklynServerConfig.BROOKLYN_CATALOG_URL,
 BrooklynRestApiLauncher.SCANNING_CATALOG_BOM_URL);
+        // sets URLs for a surefire
+        
((LocalManagementContext)manager).setBaseClassPathForScanning(ClasspathHelper.forJavaClassPath());
+        // this also works
+//        
((LocalManagementContext)manager).setBaseClassPathForScanning(ClasspathHelper.forPackage("brooklyn"));
+        // but this (near-default behaviour) does not
+//        
((LocalManagementContext)manager).setBaseClassLoader(getClass().getClassLoader());
+    }
+
+    public static void enableAnyoneLogin(Server server) {
+        ManagementContext mgmt = 
getManagementContextFromJettyServerAttributes(server);
+        enableAnyoneLogin(mgmt);
+    }
+
+    public static void enableAnyoneLogin(ManagementContext mgmt) {
+        
((BrooklynProperties)mgmt.getConfig()).put(BrooklynWebConfig.SECURITY_PROVIDER_CLASSNAME,
 
+                AnyoneSecurityProvider.class.getName());
+    }
+
+    public static ManagementContext 
getManagementContextFromJettyServerAttributes(Server server) {
+        return (ManagementContext) ((ContextHandler) 
server.getHandler()).getAttribute(BrooklynServiceAttributes.BROOKLYN_MANAGEMENT_CONTEXT);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9e5ca55/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaHotCheckTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaHotCheckTest.java 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaHotCheckTest.java
new file mode 100644
index 0000000..f78e196
--- /dev/null
+++ 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaHotCheckTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.rest;
+
+import static org.testng.Assert.assertEquals;
+
+import javax.ws.rs.core.MediaType;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.management.ha.HighAvailabilityManager;
+import brooklyn.management.ha.HighAvailabilityMode;
+import brooklyn.management.ha.ManagementNodeState;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.rest.filter.HaHotCheckResourceFilter;
+import org.apache.brooklyn.rest.filter.HaMasterCheckFilter;
+import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
+import org.apache.brooklyn.rest.util.HaHotStateCheckClassResource;
+import org.apache.brooklyn.rest.util.HaHotStateCheckResource;
+
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource.Builder;
+import com.sun.jersey.api.core.ResourceConfig;
+
+public class HaHotCheckTest extends BrooklynRestResourceTest {
+
+    // setup and teardown before/after each method
+    
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() throws Exception { super.setUp(); }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws Exception { super.tearDown(); }
+    
+    @Override
+    protected void addBrooklynResources() {
+        
config.getProperties().put(ResourceConfig.PROPERTY_RESOURCE_FILTER_FACTORIES, 
+            new HaHotCheckResourceFilter(getManagementContext()));
+        addResource(new HaHotStateCheckResource());
+        addResource(new HaHotStateCheckClassResource());
+        
+        ((LocalManagementContext)getManagementContext()).noteStartupComplete();
+    }
+
+    @Test
+    public void testHaCheck() {
+        HighAvailabilityManager ha = 
getManagementContext().getHighAvailabilityManager();
+        assertEquals(ha.getNodeState(), ManagementNodeState.MASTER);
+        testResourceFetch("/ha/method/ok", 200);
+        testResourceFetch("/ha/method/fail", 200);
+        testResourceFetch("/ha/class/fail", 200);
+
+        
getManagementContext().getHighAvailabilityManager().changeMode(HighAvailabilityMode.STANDBY);
+        assertEquals(ha.getNodeState(), ManagementNodeState.STANDBY);
+
+        testResourceFetch("/ha/method/ok", 200);
+        testResourceFetch("/ha/method/fail", 403);
+        testResourceFetch("/ha/class/fail", 403);
+
+        ((ManagementContextInternal)getManagementContext()).terminate();
+        assertEquals(ha.getNodeState(), ManagementNodeState.TERMINATED);
+
+        testResourceFetch("/ha/method/ok", 200);
+        testResourceFetch("/ha/method/fail", 403);
+        testResourceFetch("/ha/class/fail", 403);
+    }
+
+    @Test
+    public void testHaCheckForce() {
+        HighAvailabilityManager ha = 
getManagementContext().getHighAvailabilityManager();
+        assertEquals(ha.getNodeState(), ManagementNodeState.MASTER);
+        testResourceForcedFetch("/ha/method/ok", 200);
+        testResourceForcedFetch("/ha/method/fail", 200);
+        testResourceForcedFetch("/ha/class/fail", 200);
+
+        
getManagementContext().getHighAvailabilityManager().changeMode(HighAvailabilityMode.STANDBY);
+        assertEquals(ha.getNodeState(), ManagementNodeState.STANDBY);
+
+        testResourceForcedFetch("/ha/method/ok", 200);
+        testResourceForcedFetch("/ha/method/fail", 200);
+        testResourceForcedFetch("/ha/class/fail", 200);
+
+        ((ManagementContextInternal)getManagementContext()).terminate();
+        assertEquals(ha.getNodeState(), ManagementNodeState.TERMINATED);
+
+        testResourceForcedFetch("/ha/method/ok", 200);
+        testResourceForcedFetch("/ha/method/fail", 200);
+        testResourceForcedFetch("/ha/class/fail", 200);
+    }
+
+
+    private void testResourceFetch(String resourcePath, int code) {
+        testResourceFetch(resourcePath, false, code);
+    }
+
+    private void testResourceForcedFetch(String resourcePath, int code) {
+        testResourceFetch(resourcePath, true, code);
+    }
+
+    private void testResourceFetch(String resourcePath, boolean force, int 
code) {
+        Builder resource = client().resource(resourcePath)
+                .accept(MediaType.APPLICATION_JSON_TYPE);
+        if (force) {
+            resource.header(HaMasterCheckFilter.SKIP_CHECK_HEADER, "true");
+        }
+        ClientResponse response = resource
+                .get(ClientResponse.class);
+        assertEquals(response.getStatus(), code);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9e5ca55/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaMasterCheckFilterTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaMasterCheckFilterTest.java
 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaMasterCheckFilterTest.java
new file mode 100644
index 0000000..e2b6875
--- /dev/null
+++ 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaMasterCheckFilterTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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.rest;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.File;
+import java.net.URI;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.HttpClient;
+import org.eclipse.jetty.server.Server;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.BasicApplication;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.rebind.RebindTestUtils;
+import brooklyn.management.EntityManager;
+import brooklyn.management.ManagementContext;
+import brooklyn.management.ha.HighAvailabilityMode;
+import brooklyn.management.ha.ManagementNodeState;
+import org.apache.brooklyn.rest.security.provider.AnyoneSecurityProvider;
+import brooklyn.test.Asserts;
+import brooklyn.util.http.HttpTool;
+import brooklyn.util.http.HttpToolResponse;
+import brooklyn.util.os.Os;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Predicates;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
+
+public class HaMasterCheckFilterTest extends 
BrooklynRestApiLauncherTestFixture {
+    private static final Duration TIMEOUT = Duration.THIRTY_SECONDS;
+
+    private File mementoDir;
+    private ManagementContext writeMgmt;
+    private ManagementContext readMgmt;
+    private String appId;
+    private Server server;
+    private HttpClient client;
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+System.err.println("TEAR DOWN");
+        server.stop();
+        Entities.destroyAll(writeMgmt);
+        Entities.destroyAll(readMgmt);
+        Os.deleteRecursively(mementoDir);
+    }
+
+    @Test(groups = "Integration")
+    public void testEntitiesExistOnDisabledHA() throws Exception {
+        initHaCluster(HighAvailabilityMode.DISABLED, 
HighAvailabilityMode.DISABLED);
+        assertReadIsMaster();
+        assertEntityExists(new ReturnCodeCheck());
+    }
+
+    @Test(groups = "Integration")
+    public void testEntitiesExistOnMasterPromotion() throws Exception {
+        initHaCluster(HighAvailabilityMode.AUTO, HighAvailabilityMode.AUTO);
+        stopWriteNode();
+        assertEntityExists(new ReturnCodeCheck());
+        assertReadIsMaster();
+    }
+
+    @Test(groups = "Integration")
+    public void testEntitiesExistOnHotStandbyAndPromotion() throws Exception {
+        initHaCluster(HighAvailabilityMode.AUTO, 
HighAvailabilityMode.HOT_STANDBY);
+        assertEntityExists(new ReturnCodeCheck());
+        stopWriteNode();
+        assertEntityExists(new ReturnCodeAndNodeState());
+        assertReadIsMaster();
+    }
+
+    @Test(groups = "Integration")
+    public void testEntitiesExistOnHotBackup() throws Exception {
+        initHaCluster(HighAvailabilityMode.AUTO, 
HighAvailabilityMode.HOT_BACKUP);
+        Asserts.continually(
+                ImmutableMap.<String,Object>of(
+                        "timeout", Duration.THIRTY_SECONDS,
+                        "period", Duration.ZERO),
+                new ReturnCodeSupplier(),
+                Predicates.or(Predicates.equalTo(200), 
Predicates.equalTo(403)));
+    }
+
+    private HttpClient getClient(Server server) {
+        HttpClient client = HttpTool.httpClientBuilder()
+                .uri(getBaseUri(server))
+                .build();
+        return client;
+    }
+
+    private int getAppResponseCode() {
+        HttpToolResponse response = HttpTool.httpGet(
+                client, URI.create(getBaseUri(server) + "/v1/applications/" + 
appId),
+                ImmutableMap.<String,String>of());
+        return response.getResponseCode();
+    }
+
+    private String createApp(ManagementContext mgmt) {
+        EntityManager entityMgr = mgmt.getEntityManager();
+        Entity app = 
entityMgr.createEntity(EntitySpec.create(BasicApplication.class));
+        entityMgr.manage(app);
+        return app.getId();
+    }
+
+    private ManagementContext createManagementContext(File mementoDir, 
HighAvailabilityMode mode) {
+        ManagementContext mgmt = 
RebindTestUtils.managementContextBuilder(mementoDir, 
getClass().getClassLoader())
+                .persistPeriodMillis(1)
+                .forLive(false)
+                .emptyCatalog(true)
+                .buildUnstarted();
+
+        if (mode == HighAvailabilityMode.DISABLED) {
+            mgmt.getHighAvailabilityManager().disabled();
+        } else {
+            mgmt.getHighAvailabilityManager().start(mode);
+        }
+
+        new BrooklynCampPlatformLauncherNoServer()
+            .useManagementContext(mgmt)
+            .launch();
+
+        return mgmt;
+    }
+
+    private void initHaCluster(HighAvailabilityMode writeMode, 
HighAvailabilityMode readMode) throws InterruptedException, TimeoutException {
+        mementoDir = Os.newTempDir(getClass());
+
+        writeMgmt = createManagementContext(mementoDir, writeMode);
+        appId = createApp(writeMgmt);
+        writeMgmt.getRebindManager().waitForPendingComplete(TIMEOUT, true);
+
+        if (readMode == HighAvailabilityMode.DISABLED) {
+            //no HA, one node only
+            readMgmt = writeMgmt;
+        } else {
+            readMgmt = createManagementContext(mementoDir, readMode);
+        }
+
+        server = useServerForTest(BrooklynRestApiLauncher.launcher()
+                .managementContext(readMgmt)
+                .securityProvider(AnyoneSecurityProvider.class)
+                .forceUseOfDefaultCatalogWithJavaClassPath(true)
+                .withoutJsgui()
+                .disableHighAvailability(false)
+                .start());
+        client = getClient(server);
+    }
+
+    private void assertEntityExists(Callable<Integer> c) {
+        assertEquals((int)Asserts.succeedsEventually(c), 200);
+    }
+
+    private void assertReadIsMaster() {
+        assertEquals(readMgmt.getHighAvailabilityManager().getNodeState(), 
ManagementNodeState.MASTER);
+    }
+
+    private void stopWriteNode() {
+        writeMgmt.getHighAvailabilityManager().stop();
+    }
+
+    private class ReturnCodeCheck implements Callable<Integer> {
+        @Override
+        public Integer call() {
+            int retCode = getAppResponseCode();
+            if (retCode == 403) {
+                throw new RuntimeException("Not ready, retry. Response - " + 
retCode);
+            } else {
+                return retCode;
+            }
+        }
+    }
+
+    private class ReturnCodeAndNodeState extends ReturnCodeCheck {
+        @Override
+        public Integer call() {
+            Integer ret = super.call();
+            if (ret == HttpStatus.SC_OK) {
+                ManagementNodeState state = 
readMgmt.getHighAvailabilityManager().getNodeState();
+                if (state != ManagementNodeState.MASTER) {
+                    throw new RuntimeException("Not master yet " + state);
+                }
+            }
+            return ret;
+        }
+    }
+
+    private class ReturnCodeSupplier implements Supplier<Integer> {
+        @Override
+        public Integer get() {
+            return getAppResponseCode();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9e5ca55/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/ApplicationTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/ApplicationTest.java
 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/ApplicationTest.java
new file mode 100644
index 0000000..09100f5
--- /dev/null
+++ 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/ApplicationTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.rest.domain;
+
+import static brooklyn.rest.util.RestApiTestUtils.asJson;
+import static brooklyn.rest.util.RestApiTestUtils.fromJson;
+import static brooklyn.rest.util.RestApiTestUtils.jsonFixture;
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Map;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.Entities;
+import brooklyn.management.ManagementContext;
+import brooklyn.rest.domain.ApplicationSpec;
+import brooklyn.rest.domain.ApplicationSummary;
+import brooklyn.rest.domain.EntitySpec;
+import brooklyn.rest.domain.Status;
+import brooklyn.test.entity.TestApplicationImpl;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class ApplicationTest {
+
+    final EntitySpec entitySpec = new EntitySpec("Vanilla Java App", 
"brooklyn.entity.java.VanillaJavaApp",
+            ImmutableMap.<String, String>of(
+                    "initialSize", "1",
+                    "creationScriptUrl", 
"http://my.brooklyn.io/storage/foo.sql";));
+
+    final ApplicationSpec applicationSpec = 
ApplicationSpec.builder().name("myapp")
+            .entities(ImmutableSet.of(entitySpec))
+            .locations(ImmutableSet.of("/v1/locations/1"))
+            .build();
+
+    final ApplicationSummary application = new ApplicationSummary(null, 
applicationSpec, Status.STARTING, null);
+
+    @SuppressWarnings("serial")
+    @Test
+    public void testSerializeToJSON() throws IOException {
+        ApplicationSummary application1 = new ApplicationSummary("myapp_id", 
applicationSpec, Status.STARTING, null) {
+            @Override
+            public Map<String, URI> getLinks() {
+                return ImmutableMap.of(
+                        "self", URI.create("/v1/applications/" + 
applicationSpec.getName()),
+                        "entities", 
URI.create("fixtures/entity-summary-list.json"));
+            }
+        };
+        assertEquals(asJson(application1), 
jsonFixture("fixtures/application.json"));
+    }
+
+    @Test
+    public void testDeserializeFromJSON() throws IOException {
+        assertEquals(fromJson(jsonFixture("fixtures/application.json"),
+                ApplicationSummary.class), application);
+    }
+
+    @Test
+    public void testTransitionToRunning() {
+        ApplicationSummary running = application.transitionTo(Status.RUNNING);
+        assertEquals(running.getStatus(), Status.RUNNING);
+    }
+
+    @Test
+    public void testAppInAppTest() throws IOException {
+        TestApplicationImpl app = new TestApplicationImpl();
+        ManagementContext mgmt = Entities.startManagement(app);
+        try {
+            Entity e2 = app.addChild(new TestApplicationImpl());
+            Entities.manage(e2);
+            if (mgmt.getApplications().size()!=1)
+                Assert.fail("Apps in Apps should not be listed at top level: 
"+mgmt.getApplications());
+        } finally {
+            Entities.destroyAll(mgmt);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9e5ca55/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/LocationSummaryTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/LocationSummaryTest.java
 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/LocationSummaryTest.java
new file mode 100644
index 0000000..0df8fcc
--- /dev/null
+++ 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/LocationSummaryTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.rest.domain;
+
+import brooklyn.rest.domain.LocationSpec;
+import brooklyn.rest.domain.LocationSummary;
+import static brooklyn.rest.util.RestApiTestUtils.asJson;
+import static brooklyn.rest.util.RestApiTestUtils.fromJson;
+import static brooklyn.rest.util.RestApiTestUtils.jsonFixture;
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+import org.codehaus.jackson.type.TypeReference;
+import org.testng.annotations.Test;
+
+import org.apache.brooklyn.rest.transform.LocationTransformer;
+
+public class LocationSummaryTest {
+
+    @SuppressWarnings("deprecation")
+    final LocationSummary summary = LocationTransformer.newInstance("123", 
LocationSpec.localhost());
+
+    @Test
+    public void testSerializeToJSON() throws IOException {
+        assertEquals(asJson(summary), 
jsonFixture("fixtures/location-summary.json"));
+    }
+
+    @Test
+    public void testDeserializeFromJSON() throws IOException {
+        assertEquals(fromJson(jsonFixture("fixtures/location-summary.json"), 
LocationSummary.class), summary);
+    }
+
+    @Test
+    public void testDeserializeListFromJSON() throws IOException {
+        assertEquals(fromJson(jsonFixture("fixtures/location-list.json"), new 
TypeReference<List<LocationSummary>>() {}), 
+                Collections.singletonList(summary));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9e5ca55/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/SensorSummaryTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/SensorSummaryTest.java
 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/SensorSummaryTest.java
new file mode 100644
index 0000000..24e31ec
--- /dev/null
+++ 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/SensorSummaryTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.rest.domain;
+
+import static brooklyn.rest.util.RestApiTestUtils.asJson;
+import static brooklyn.rest.util.RestApiTestUtils.fromJson;
+import static brooklyn.rest.util.RestApiTestUtils.jsonFixture;
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.config.render.RendererHints;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.Sensor;
+import brooklyn.event.basic.Sensors;
+import brooklyn.management.ManagementContext;
+import brooklyn.rest.domain.SensorSummary;
+import org.apache.brooklyn.rest.transform.SensorTransformer;
+import brooklyn.test.entity.TestApplication;
+import brooklyn.test.entity.TestEntity;
+
+import com.google.common.collect.ImmutableMap;
+
+public class SensorSummaryTest {
+
+    private SensorSummary sensorSummary = new SensorSummary("redis.uptime", 
"Integer",
+            "Description", ImmutableMap.of(
+            "self", 
URI.create("/v1/applications/redis-app/entities/redis-ent/sensors/redis.uptime")));
+
+    private TestApplication app;
+    private TestEntity entity;
+    private ManagementContext mgmt;
+
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() throws Exception {
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        mgmt = app.getManagementContext();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws Exception {
+        if (mgmt != null) Entities.destroyAll(mgmt);
+    }
+
+    @Test
+    public void testSerializeToJSON() throws IOException {
+        assertEquals(asJson(sensorSummary), 
jsonFixture("fixtures/sensor-summary.json"));
+    }
+
+    @Test
+    public void testDeserializeFromJSON() throws IOException {
+        assertEquals(fromJson(jsonFixture("fixtures/sensor-summary.json"), 
SensorSummary.class), sensorSummary);
+    }
+
+    @Test
+    public void testEscapesUriForSensorName() throws IOException {
+        Sensor<String> sensor = Sensors.newStringSensor("name with space");
+        SensorSummary summary = SensorTransformer.sensorSummary(entity, 
sensor);
+        URI selfUri = summary.getLinks().get("self");
+
+        String expectedUri = "/v1/applications/" + entity.getApplicationId() + 
"/entities/" + entity.getId() + "/sensors/" + "name%20with%20space";
+
+        assertEquals(selfUri, URI.create(expectedUri));
+    }
+
+    // Previously failed because immutable-map builder threw exception if put 
same key multiple times,
+    // and the NamedActionWithUrl did not have equals/hashCode
+    @Test
+    public void testSensorWithMultipleOpenUrlActionsRegistered() throws 
IOException {
+        AttributeSensor<String> sensor = Sensors.newStringSensor("sensor1");
+        entity.setAttribute(sensor, "http://myval";);
+        RendererHints.register(sensor, RendererHints.namedActionWithUrl());
+        RendererHints.register(sensor, RendererHints.namedActionWithUrl());
+
+        SensorSummary summary = SensorTransformer.sensorSummary(entity, 
sensor);
+
+        assertEquals(summary.getLinks().get("action:open"), 
URI.create("http://myval";));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9e5ca55/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/AccessResourceTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/AccessResourceTest.java
 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/AccessResourceTest.java
new file mode 100644
index 0000000..edce6ba
--- /dev/null
+++ 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/AccessResourceTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.rest.resources;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import javax.ws.rs.core.Response;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.rest.domain.AccessSummary;
+import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
+
+import com.sun.jersey.api.client.ClientResponse;
+
+@Test(singleThreaded = true)
+public class AccessResourceTest extends BrooklynRestResourceTest {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = 
LoggerFactory.getLogger(AccessResourceTest.class);
+
+    @Test
+    public void testGetAndSetAccessControl() throws Exception {
+        // Default is everything allowed
+        AccessSummary summary = 
client().resource("/v1/access").get(AccessSummary.class);
+        assertTrue(summary.isLocationProvisioningAllowed());
+
+        // Forbid location provisioning
+        ClientResponse response = client().resource(
+                "/v1/access/locationProvisioningAllowed")
+                .queryParam("allowed", "false")
+                .post(ClientResponse.class);
+        assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
+
+        AccessSummary summary2 = 
client().resource("/v1/access").get(AccessSummary.class);
+        assertFalse(summary2.isLocationProvisioningAllowed());
+        
+        // Allow location provisioning
+        ClientResponse response2 = client().resource(
+                "/v1/access/locationProvisioningAllowed")
+                .queryParam("allowed", "true")
+                .post(ClientResponse.class);
+        assertEquals(response2.getStatus(), 
Response.Status.OK.getStatusCode());
+
+        AccessSummary summary3 = 
client().resource("/v1/access").get(AccessSummary.class);
+        assertTrue(summary3.isLocationProvisioningAllowed());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9e5ca55/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ApiDocResourceTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ApiDocResourceTest.java
 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ApiDocResourceTest.java
new file mode 100644
index 0000000..29e4d22
--- /dev/null
+++ 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ApiDocResourceTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.rest.resources;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import org.apache.brooklyn.rest.BrooklynRestApi;
+import brooklyn.rest.apidoc.ApidocRoot;
+import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.wordnik.swagger.core.DocumentationEndPoint;
+import com.wordnik.swagger.core.DocumentationOperation;
+
+/**
+ * @author Adam Lowe
+ */
+@Test(singleThreaded = true)
+public class ApiDocResourceTest extends BrooklynRestResourceTest {
+
+    private static final Logger log = 
LoggerFactory.getLogger(ApiDocResourceTest.class);
+
+    @Override
+    protected void addBrooklynResources() {
+        for (Object o : BrooklynRestApi.getApidocResources()) {
+            addResource(o);
+        }
+        super.addBrooklynResources();
+    }
+    
+    @Test
+    public void testRootSerializesSensibly() throws Exception {
+        String data = client().resource("/v1/apidoc/").get(String.class);
+        log.info("apidoc gives: "+data);
+        // make sure no scala gets in
+        Assert.assertFalse(data.contains("$"));
+        Assert.assertFalse(data.contains("scala"));
+    }
+    
+    @Test
+    public void testCountRestResources() throws Exception {
+        ApidocRoot response = 
client().resource("/v1/apidoc/").get(ApidocRoot.class);
+        assertEquals(response.getApis().size(), 1 + 
Iterables.size(BrooklynRestApi.getBrooklynRestResources()));
+    }
+
+    @Test
+    public void testEndpointSerializesSensibly() throws Exception {
+        String data = 
client().resource("/v1/apidoc/org.apache.brooklyn.rest.resources.ApidocResource").get(String.class);
+        log.info("apidoc endpoint resource gives: "+data);
+        // make sure no scala gets in
+        Assert.assertFalse(data.contains("$"));
+        Assert.assertFalse(data.contains("scala"));
+    }
+    
+    @Test
+    public void testApiDocDetails() throws Exception {
+        ApidocRoot response = 
client().resource("/v1/apidoc/org.apache.brooklyn.rest.resources.ApidocResource").get(ApidocRoot.class);
+        assertEquals(countOperations(response), 2);
+    }
+
+    @Test
+    public void testEffectorDetails() throws Exception {
+        ApidocRoot response = 
client().resource("/v1/apidoc/org.apache.brooklyn.rest.resources.EffectorResource").get(ApidocRoot.class);
+        assertEquals(countOperations(response), 2);
+    }
+
+    @Test
+    public void testEntityDetails() throws Exception {
+        ApidocRoot response = 
client().resource("/v1/apidoc/org.apache.brooklyn.rest.resources.EntityResource").get(ApidocRoot.class);
+        assertEquals(countOperations(response), 14);
+    }
+
+    @Test
+    public void testCatalogDetails() throws Exception {
+        ApidocRoot response = 
client().resource("/v1/apidoc/org.apache.brooklyn.rest.resources.CatalogResource").get(ApidocRoot.class);
+        assertEquals(countOperations(response), 22, 
"ops="+getOperations(response));
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Test
+    public void testAllAreLoadable() throws Exception {
+        // sometimes -- e.g. if an annotation refers to a class name with the 
wrong case -- the call returns a 500 and breaks apidoc; ensure we don't trigger 
that.  
+        Map response = client().resource("/v1/apidoc/").get(Map.class);
+        // "Documenation" object does not include the links :( so traverse via 
map
+        log.debug("root doc response is: "+response);
+        List apis = (List)response.get("apis");
+        for (Object api: apis) {
+            String link = (String) ((Map)api).get("link");
+            try {
+                Map r2 = client().resource(link).get(Map.class);
+                log.debug("doc for "+link+" is: "+r2);
+            } catch (Exception e) {
+                log.error("Error in swagger/apidoc annotations, unparseable, 
at "+link+": "+e, e);
+                Assert.fail("Error in swagger/apidoc annotations, unparseable, 
at "+link+": "+e, e);
+            }
+        }
+    }
+
+    /* Note in some cases we might have more than one Resource method per 
'endpoint'
+     */
+    private int countOperations(ApidocRoot doc) throws Exception {
+        return getOperations(doc).size();
+    }
+    
+    private List<DocumentationOperation> getOperations(ApidocRoot doc) throws 
Exception {
+        List<DocumentationOperation> result = Lists.newArrayList();
+        for (DocumentationEndPoint endpoint : doc.getApis()) {
+            result.addAll(endpoint.getOperations());
+        }
+        return result;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9e5ca55/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceIntegrationTest.java
 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceIntegrationTest.java
new file mode 100644
index 0000000..3ae6377
--- /dev/null
+++ 
b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceIntegrationTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.rest.resources;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.Set;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.Lifecycle;
+import brooklyn.rest.domain.ApplicationSpec;
+import brooklyn.rest.domain.ApplicationSummary;
+import brooklyn.rest.domain.EntitySpec;
+import brooklyn.rest.domain.EntitySummary;
+import brooklyn.rest.domain.SensorSummary;
+import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
+import brooklyn.test.Asserts;
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.GenericType;
+
+@Test(singleThreaded = true)
+public class ApplicationResourceIntegrationTest extends 
BrooklynRestResourceTest {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = 
LoggerFactory.getLogger(ApplicationResourceIntegrationTest.class);
+
+    private final ApplicationSpec redisSpec = 
ApplicationSpec.builder().name("redis-app")
+            .entities(ImmutableSet.of(new EntitySpec("redis-ent", 
"org.apache.brooklyn.entity.nosql.redis.RedisStore")))
+            .locations(ImmutableSet.of("localhost"))
+            .build();
+
+    @Test(groups="Integration")
+    public void testDeployRedisApplication() throws Exception {
+        ClientResponse response = clientDeploy(redisSpec);
+
+        assertEquals(response.getStatus(), 201);
+        assertEquals(getManagementContext().getApplications().size(), 1);
+        
assertTrue(response.getLocation().getPath().startsWith("/v1/applications/"), 
"path="+response.getLocation().getPath()); // path uses id, rather than app name
+
+        waitForApplicationToBeRunning(response.getLocation());
+    }
+
+    @Test(groups="Integration", dependsOnMethods = 
"testDeployRedisApplication")
+    public void testListEntities() {
+        Set<EntitySummary> entities = 
client().resource("/v1/applications/redis-app/entities")
+                .get(new GenericType<Set<EntitySummary>>() {});
+
+        for (EntitySummary entity : entities) {
+            
client().resource(entity.getLinks().get("self")).get(ClientResponse.class);
+            // TODO assertions on the above call?
+
+            Set<EntitySummary> children = 
client().resource(entity.getLinks().get("children"))
+                    .get(new GenericType<Set<EntitySummary>>() {});
+            assertEquals(children.size(), 0);
+        }
+    }
+
+    @Test(groups="Integration", dependsOnMethods = 
"testDeployRedisApplication")
+    public void testListSensorsRedis() {
+        Set<SensorSummary> sensors = 
client().resource("/v1/applications/redis-app/entities/redis-ent/sensors")
+                .get(new GenericType<Set<SensorSummary>>() {});
+        assertTrue(sensors.size() > 0);
+        SensorSummary uptime = Iterables.find(sensors, new 
Predicate<SensorSummary>() {
+            @Override
+            public boolean apply(SensorSummary sensorSummary) {
+                return sensorSummary.getName().equals("redis.uptime");
+            }
+        });
+        assertEquals(uptime.getType(), "java.lang.Integer");
+    }
+
+    @Test(groups="Integration", dependsOnMethods = { "testListSensorsRedis", 
"testListEntities" })
+    public void testTriggerRedisStopEffector() throws Exception {
+        ClientResponse response = 
client().resource("/v1/applications/redis-app/entities/redis-ent/effectors/stop")
+                .type(MediaType.APPLICATION_JSON_TYPE)
+                .post(ClientResponse.class, ImmutableMap.of());
+        assertEquals(response.getStatus(), 
Response.Status.ACCEPTED.getStatusCode());
+
+        final URI stateSensor = 
URI.create("/v1/applications/redis-app/entities/redis-ent/sensors/service.state");
+        final String expectedStatus = Lifecycle.STOPPED.toString();
+        Asserts.succeedsEventually(MutableMap.of("timeout", 60 * 1000), new 
Runnable() {
+            public void run() {
+                // Accept with and without quotes; if don't specify "Accepts" 
header, then
+                // might get back json or plain text (depending on compiler / 
java runtime 
+                // used for SensorApi!)
+                String val = client().resource(stateSensor).get(String.class);
+                assertTrue(expectedStatus.equalsIgnoreCase(val) || 
("\""+expectedStatus+"\"").equalsIgnoreCase(val), "state="+val);
+            }
+        });
+    }
+
+    @Test(groups="Integration", dependsOnMethods = 
"testTriggerRedisStopEffector" )
+    public void testDeleteRedisApplication() throws Exception {
+        int size = getManagementContext().getApplications().size();
+        ClientResponse response = 
client().resource("/v1/applications/redis-app")
+                .delete(ClientResponse.class);
+
+        waitForPageNotFoundResponse("/v1/applications/redis-app", 
ApplicationSummary.class);
+
+        assertEquals(response.getStatus(), 
Response.Status.ACCEPTED.getStatusCode());
+        assertEquals(getManagementContext().getApplications().size(), size-1);
+    }
+
+}

Reply via email to