package org.cloudfoundry.client.lib;
import static java.util.Arrays.asList;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.io.IOUtils;
import org.cloudfoundry.client.lib.domain.ApplicationLog;
import org.cloudfoundry.client.lib.domain.ApplicationStats;
import org.cloudfoundry.client.lib.domain.CloudApplication;
import org.cloudfoundry.client.lib.domain.CloudDomain;
import org.cloudfoundry.client.lib.domain.CloudEntity;
import org.cloudfoundry.client.lib.domain.CloudInfo;
import org.cloudfoundry.client.lib.domain.CloudOrganization;
import org.cloudfoundry.client.lib.domain.CloudRoute;
import org.cloudfoundry.client.lib.domain.CloudService;
import org.cloudfoundry.client.lib.domain.CloudServiceBroker;
import org.cloudfoundry.client.lib.domain.CloudServiceOffering;
import org.cloudfoundry.client.lib.domain.CloudServicePlan;
import org.cloudfoundry.client.lib.domain.CloudSpace;
import org.cloudfoundry.client.lib.domain.CloudStack;
import org.cloudfoundry.client.lib.domain.CrashInfo;
import org.cloudfoundry.client.lib.domain.CrashesInfo;
import org.cloudfoundry.client.lib.domain.InstanceInfo;
import org.cloudfoundry.client.lib.domain.InstanceState;
import org.cloudfoundry.client.lib.domain.InstanceStats;
import org.cloudfoundry.client.lib.domain.InstancesInfo;
import org.cloudfoundry.client.lib.domain.Staging;
import org.cloudfoundry.client.lib.util.RestUtil;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ConnectHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.jboss.byteman.contrib.bmunit.BMScript;
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestTemplate;
import org.cloudfoundry.client.lib.domain.CloudQuota;
/**
* Note that this integration tests rely on other methods working correctly, so these tests aren't
* independent unit tests for all methods, they are intended to test the completeness of the functionality of
* each API version implementation.
*
* @author Ramnivas Laddad
* @author A.B.Srinivasan
* @author Jennifer Hickey
* @author Thomas Risberg
*/
@RunWith(BMUnitRunner.class)
@BMScript(value="trace", dir="target/test-classes")
public class CloudFoundryClientTest {
private CloudFoundryClient connectedClient;
// Pass -Dccng.target=http://api.cloudfoundry.com, vcap.me, or your own cloud -- must point to a v2 cloud controller
private static final String CCNG_API_URL = System.getProperty("ccng.target", "http://api.run.pivotal.io");
private static final String CCNG_API_PROXY_HOST = System.getProperty("http.proxyHost", null);
private static final int CCNG_API_PROXY_PORT = Integer.getInteger("http.proxyPort", 80);
private static final String CCNG_API_PROXY_USER = System.getProperty("http.proxyUsername", null);
private static final String CCNG_API_PROXY_PASSWD = System.getProperty("http.proxyPassword", null);
private static final boolean CCNG_API_SSL = Boolean.getBoolean("ccng.ssl");
private static final String CCNG_USER_EMAIL = System.getProperty("ccng.email", "java-authenticatedClient-test-user@vmware.com");
private static final String CCNG_USER_PASS = System.getProperty("ccng.passwd");
private static final boolean CCNG_USER_IS_ADMIN = Boolean.getBoolean("ccng.admin");
private static final String CCNG_USER_ORG = System.getProperty("ccng.org", "gopivotal.com");
private static final String CCNG_USER_SPACE = System.getProperty("ccng.space", "test");
private static final String TEST_NAMESPACE = System.getProperty("vcap.test.namespace", defaultNamespace(CCNG_USER_EMAIL));
private static final String TEST_DOMAIN = System.getProperty("vcap.test.domain", defaultNamespace(CCNG_USER_EMAIL) + ".com");
private static final String MYSQL_SERVICE_LABEL = System.getProperty("vcap.mysql.label", "p-mysql");
private static final String MYSQL_SERVICE_PLAN = System.getProperty("vcap.mysql.plan", "100mb-dev");
private static final String DEFAULT_STACK_NAME = "lucid64";
private static final boolean SILENT_TEST_TIMINGS = Boolean.getBoolean("silent.testTimings");
private static final boolean SKIP_INJVM_PROXY = Boolean.getBoolean("http.skipInJvmProxy");
public static final int STARTUP_TIMEOUT = Integer.getInteger("ccng.startup.timeout", 60000);
private static String defaultDomainName = null;
private static HttpProxyConfiguration httpProxyConfiguration;
private static Server inJvmProxyServer;
private static int inJvmProxyPort;
private static AtomicInteger nbInJvmProxyRcvReqs;
private static final int DEFAULT_MEMORY = 512; // MB
private static final int DEFAULT_DISK = 1024; // MB
private static final int FIVE_MINUTES = 300 * 1000;
private static final String CCNG_QUOTA_NAME_TEST = System.getProperty("ccng.quota", "test_quota");
private static boolean tearDownComplete = false;
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Rule
public ExpectedException thrown = ExpectedException.none();
@Rule
public TestRule watcher = new TestWatcher() {
private long startTime;
@Override
protected void starting(Description description) {
if (!SILENT_TEST_TIMINGS) {
System.out.println("Starting test " + description.getMethodName());
}
startTime = System.currentTimeMillis();
}
@Override
protected void finished(Description description) {
if (!SILENT_TEST_TIMINGS) {
System.out.println("Test " + description.getMethodName() + " took " + (System.currentTimeMillis() - startTime) + " ms");
}
}
};
@BeforeClass
public static void beforeClass() throws Exception {
System.out.println("Running tests on " + CCNG_API_URL + " on behalf of " + CCNG_USER_EMAIL);
System.out.println("Using space " + CCNG_USER_SPACE + " of organization " + CCNG_USER_ORG );
if (CCNG_USER_PASS == null) {
fail("System property ccng.passwd must be specified, supply -Dccng.passwd=<password>");
}
if (CCNG_API_PROXY_HOST != null) {
if (CCNG_API_PROXY_USER != null) {
httpProxyConfiguration = new HttpProxyConfiguration(CCNG_API_PROXY_HOST, CCNG_API_PROXY_PORT, true, CCNG_API_PROXY_USER, CCNG_API_PROXY_PASSWD);
} else {
httpProxyConfiguration = new HttpProxyConfiguration(CCNG_API_PROXY_HOST, CCNG_API_PROXY_PORT);
}
}
if (!SKIP_INJVM_PROXY) {
startInJvmProxy();
httpProxyConfiguration = new HttpProxyConfiguration("127.0.0.1", inJvmProxyPort);
}
}
@AfterClass
public static void afterClass() throws Exception {
if (inJvmProxyServer != null) {
inJvmProxyServer.stop();
nbInJvmProxyRcvReqs.set(0);
}
}
@Before
public void setUp() throws Exception {
URL cloudControllerUrl;
cloudControllerUrl = new URL(CCNG_API_URL);
connectedClient = new CloudFoundryClient(new CloudCredentials(CCNG_USER_EMAIL, CCNG_USER_PASS),
cloudControllerUrl, CCNG_USER_ORG, CCNG_USER_SPACE, httpProxyConfiguration, CCNG_API_SSL);
connectedClient.login();
defaultDomainName = connectedClient.getDefaultDomain().getName();
// Optimization to avoid redoing the work already done is tearDown()
if (!tearDownComplete) {
tearDown();
}
tearDownComplete = false;
connectedClient.addDomain(TEST_DOMAIN);
// connectedClient.registerRestLogListener(new RestLogger("CF_REST"));
if (nbInJvmProxyRcvReqs != null) {
nbInJvmProxyRcvReqs.set(0); //reset calls made in setup to leave a clean state for tests to assert
}
if (!SKIP_INJVM_PROXY) {
new SocketDestHelper().setForbiddenOnCurrentThread();
}
}
@After
public void tearDown() throws Exception {
// Clean after ourselves so that there are no leftover apps, services, domains, and routes
if (connectedClient != null) { //may happen if setUp() fails
connectedClient.deleteAllApplications();
connectedClient.deleteAllServices();
clearTestDomainAndRoutes();
}
tearDownComplete = true;
}
@Test
public void infoAvailable() throws Exception {
CloudInfo info = connectedClient.getCloudInfo();
assertNotNull(info.getName());
assertNotNull(info.getSupport());
assertNotNull(info.getBuild());
}
/**
* Self tests that the assert mechanisms with jetty and byteman are properly working. If debugging is needed
* consider enabling one or more of the following system properties
* -Dorg.jboss.byteman.verbose=true
* -Dorg.jboss.byteman.debug=true
* -Dorg.jboss.byteman.rule.debug=true
* -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
* -Dorg.eclipse.jetty.LEVEL=INFO
* -Dorg.eclipse.jetty.server.LEVEL=INFO
* -Dorg.eclipse.jetty.server.handler.ConnectHandler=DEBUG
* Documentation on byteman at http://downloads.jboss.org/byteman/2.1.3/ProgrammersGuideSinglePage.2.1.3.1.html
*/
@Test
public void checkByteManrulesAndInJvmProxyAssertMechanisms() {
if (SKIP_INJVM_PROXY) {
return; //inJvm Proxy test skipped.
}
assertTrue(SocketDestHelper.isSocketRestrictionFlagActive());
RestTemplate restTemplate = new RestTemplate();
// When called directly without a proxy, expect an exception to be thrown due to byteman rules
assertNetworkCallFails(restTemplate, new HttpComponentsClientHttpRequestFactory());
// Repeat that with different request factory used in the code as this exercises different byteman rules
assertNetworkCallFails(restTemplate, new SimpleClientHttpRequestFactory());
// And with the actual one used by RestUtil, without a proxy configured
assertNetworkCallFails(restTemplate, new RestUtil().createRequestFactory(null, false));
// Test with the in-JVM proxy configured
HttpProxyConfiguration localProxy = new HttpProxyConfiguration("127.0.0.1", inJvmProxyPort);
ClientHttpRequestFactory requestFactory = new RestUtil().createRequestFactory(localProxy, CCNG_API_SSL);
restTemplate.setRequestFactory(requestFactory);
restTemplate.execute(CCNG_API_URL + "/info", HttpMethod.GET, null, null);
// then executes fine, and the jetty proxy indeed received one request
assertEquals("expected network calls to make it through the inJvmProxy.", 1, nbInJvmProxyRcvReqs.get());
nbInJvmProxyRcvReqs.set(0); //reset for next test
assertTrue(SocketDestHelper.isActivated());
assertFalse("expected some installed rules, got:" + SocketDestHelper.getInstalledRules(), SocketDestHelper.getInstalledRules().isEmpty());
}
private void assertNetworkCallFails(RestTemplate restTemplate, ClientHttpRequestFactory requestFactory) {
restTemplate.setRequestFactory(requestFactory);
try {
HttpStatus status = restTemplate.execute(CCNG_API_URL + "/info", HttpMethod.GET, null, new ResponseExtractor<HttpStatus>() {
public HttpStatus extractData(ClientHttpResponse response) throws IOException {
return response.getStatusCode();
}
});
Assert.fail("Expected byteman rules to detect direct socket connections, status is:" + status);
} catch (Exception e) {
//good, byteman rejected it as expected
//e.printStackTrace();
}
assertEquals("Not expecting Jetty to receive requests since we asked direct connections", 0, nbInJvmProxyRcvReqs.get());
}
private static int getNextAvailablePort(int initial) {
int current = initial;
while (! PortAvailability.available(current)) {
current ++;
if (current - initial > 100) {
throw new RuntimeException("did not find an available port from " + initial + " up to:" + current);
}
}
return current;
}
/**
* To test that the CF client is able to go through a proxy, we point the CC client to a broken url
* that can only be resolved by going through an inJVM proxy which rewrites the URI.
* This method starts this inJvm proxy.
* @throws Exception
*/
private static void startInJvmProxy() throws Exception {
inJvmProxyPort = getNextAvailablePort(8080);
inJvmProxyServer = new Server(new InetSocketAddress("127.0.0.1", inJvmProxyPort)); //forcing use of loopback that will be used both for Httpclient proxy and SocketDestHelper
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setMinThreads(1);
inJvmProxyServer.setThreadPool(threadPool);
HandlerCollection handlers = new HandlerCollection();
inJvmProxyServer.setHandler(handlers);
ServletHandler servletHandler = new ServletHandler();
handlers.addHandler(servletHandler);
nbInJvmProxyRcvReqs = new AtomicInteger();
ChainedProxyServlet chainedProxyServlet = new ChainedProxyServlet(httpProxyConfiguration, nbInJvmProxyRcvReqs);
servletHandler.addServletWithMapping(new ServletHolder(chainedProxyServlet), "/*");
// Setup proxy handler to handle CONNECT methods
ConnectHandler proxyHandler;
proxyHandler = new ChainedProxyConnectHandler(httpProxyConfiguration, nbInJvmProxyRcvReqs);
handlers.addHandler(proxyHandler);
inJvmProxyServer.start();
}
@Test
public void spacesAvailable() throws Exception {
List<CloudSpace> spaces = connectedClient.getSpaces();
assertNotNull(spaces);
assertTrue(spaces.size() > 0);
}
@Test
public void orgsAvailable() throws Exception {
List<CloudOrganization> orgs = connectedClient.getOrganizations();
assertNotNull(orgs);
assertTrue(orgs.size() > 0);
}
//
// Basic Application tests
//
@Test
public void createApplication() {
String appName = namespacedAppName("travel_test-0");
List<String> uris = Arrays.asList(computeAppUrl(appName));
Staging staging = new Staging();
connectedClient.createApplication(appName, staging, DEFAULT_MEMORY, uris, null);
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(appName, app.getName());
assertNotNull(app.getMeta().getGuid());
final Calendar now = Calendar.getInstance();
now.setTime(new Date());
final Calendar createdDate = Calendar.getInstance();
createdDate.setTime(app.getMeta().getCreated());
assertEquals(now.get(Calendar.DATE), createdDate.get(Calendar.DATE));
}
@Test
public void createApplicationWithBuildPack() throws IOException {
String buildpackUrl = "https://github.com/cloudfoundry/java-buildpack.git";
String appName = namespacedAppName("buildpack");
createSpringApplication(appName, buildpackUrl);
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(CloudApplication.AppState.STOPPED, app.getState());
assertEquals(buildpackUrl, app.getStaging().getBuildpackUrl());
}
@Test
public void createApplicationWithStack() throws IOException {
String appName = namespacedAppName("stack");
createSpringApplication(appName, DEFAULT_STACK_NAME, null);
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(CloudApplication.AppState.STOPPED, app.getState());
assertEquals(DEFAULT_STACK_NAME, app.getStaging().getStack());
}
@Test
public void createApplicationWithHealthCheckTimeout() throws IOException {
String appName = namespacedAppName("health_check");
createSpringApplication(appName, null, 2);
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(CloudApplication.AppState.STOPPED, app.getState());
assertEquals(2, app.getStaging().getHealthCheckTimeout().intValue());
}
@Test
public void createApplicationWithDomainOnly() {
String appName = namespacedAppName("travel_test-tld");
connectedClient.addDomain(TEST_DOMAIN);
List<String> uris = Arrays.asList(TEST_DOMAIN);
Staging staging = new Staging();
connectedClient.createApplication(appName, staging, DEFAULT_MEMORY, uris, null);
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(appName, app.getName());
List<String> actualUris = app.getUris();
assertTrue(actualUris.size() == 1);
assertEquals(TEST_DOMAIN, actualUris.get(0));
}
@Test
public void getApplicationByName() {
final String serviceName = "test_database";
String appName = createSpringTravelApp("1", Collections.singletonList(serviceName));
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(appName, app.getName());
assertEquals(1, app.getServices().size());
assertEquals(serviceName, app.getServices().get(0));
assertEquals(1, app.getInstances());
assertEquals(DEFAULT_MEMORY, app.getMemory());
assertEquals(DEFAULT_DISK, app.getDiskQuota());
assertNull(app.getStaging().getCommand());
assertNull(app.getStaging().getBuildpackUrl());
assertNull(app.getStaging().getHealthCheckTimeout());
}
@Test
public void getApplicationByGuid() {
String appName = createSpringTravelApp("3");
CloudApplication app = connectedClient.getApplication(appName);
CloudApplication guidApp = connectedClient.getApplication(app.getMeta().getGuid());
assertEquals(app.getName(), guidApp.getName());
}
@Test
public void getApplicationNonExistent() {
thrown.expect(CloudFoundryException.class);
thrown.expect(hasProperty("statusCode", is(HttpStatus.NOT_FOUND)));
thrown.expectMessage(containsString("Not Found"));
String appName = namespacedAppName("non_existent");
connectedClient.getApplication(appName);
}
@Test
public void getApplications() {
final String serviceName = "test_database";
String appName = createSpringTravelApp("2", Collections.singletonList(serviceName));
List<CloudApplication> apps = connectedClient.getApplications();
assertEquals(1, apps.size());
CloudApplication app = apps.get(0);
assertEquals(appName, app.getName());
assertNotNull(app.getMeta());
assertNotNull(app.getMeta().getGuid());
assertEquals(1, app.getServices().size());
assertEquals(serviceName, app.getServices().get(0));
createSpringTravelApp("3");
apps = connectedClient.getApplications();
assertEquals(2, apps.size());
}
@Test
public void deleteApplication() {
String appName = createSpringTravelApp("4");
assertEquals(1, connectedClient.getApplications().size());
connectedClient.deleteApplication(appName);
assertEquals(0, connectedClient.getApplications().size());
}
@Test
public void startStopApplication() throws IOException {
String appName = createSpringTravelApp("upload-start-stop");
CloudApplication app = uploadSpringTravelApp(appName);
assertNotNull(app);
assertEquals(CloudApplication.AppState.STOPPED, app.getState());
String url = computeAppUrlNoProtocol(appName);
assertEquals(url, app.getUris().get(0));
StartingInfo info = connectedClient.startApplication(appName);
app = connectedClient.getApplication(appName);
assertEquals(CloudApplication.AppState.STARTED, app.getState());
assertNotNull(info);
assertNotNull(info.getStagingFile());
connectedClient.stopApplication(appName);
app = connectedClient.getApplication(appName);
assertEquals(CloudApplication.AppState.STOPPED, app.getState());
}
@Test
public void paginationWorksForUris() throws IOException {
String appName = namespacedAppName("page-url1");
CloudApplication app = createAndUploadSimpleTestApp(appName);
List<String> originalUris = app.getUris();
assertEquals(Collections.singletonList(computeAppUrl(appName)), originalUris);
List<String> uris = new ArrayList<String>(app.getUris());
for (int i = 2; i < 55; i++) {
uris.add(computeAppUrl(namespacedAppName("page-url" + i)));
}
connectedClient.updateApplicationUris(appName, uris);
app = connectedClient.getApplication(appName);
List<String> appUris = app.getUris();
assertNotNull(appUris);
assertEquals(uris.size(), appUris.size());
for (String uri : uris) {
assertTrue("Missing URI: " + uri, appUris.contains(uri));
}
}
//
// App configuration tests
//
@Test
public void setEnvironmentThroughList() throws IOException {
String appName = createSpringTravelApp("env1");
CloudApplication app = connectedClient.getApplication(appName);
assertTrue(app.getEnv().isEmpty());
connectedClient.updateApplicationEnv(appName, asList("foo=bar", "bar=baz"));
app = connectedClient.getApplication(app.getName());
assertEquals(new HashSet<String>(asList("foo=bar", "bar=baz")), new HashSet<String>(app.getEnv()));
connectedClient.updateApplicationEnv(appName, asList("foo=baz", "baz=bong"));
app = connectedClient.getApplication(app.getName());
assertEquals(new HashSet<String>(asList("foo=baz", "baz=bong")), new HashSet<String>(app.getEnv()));
connectedClient.updateApplicationEnv(appName, new ArrayList<String>());
app = connectedClient.getApplication(app.getName());
assertTrue(app.getEnv().isEmpty());
}
@Test
public void setEnvironmentWithoutEquals() throws IOException {
thrown.expect(IllegalArgumentException.class);
String appName = createSpringTravelApp("env2");
CloudApplication app = connectedClient.getApplication(appName);
assertTrue(app.getEnv().isEmpty());
connectedClient.updateApplicationEnv(appName, asList("foo:bar", "bar=baz"));
}
@Test
public void setEnvironmentThroughMap() throws IOException {
String appName = createSpringTravelApp("env3");
CloudApplication app = connectedClient.getApplication(appName);
assertTrue(app.getEnv().isEmpty());
Map<String, String> env1 = new HashMap<String, String>();
env1.put("foo", "bar");
env1.put("bar", "baz");
connectedClient.updateApplicationEnv(appName, env1);
app = connectedClient.getApplication(app.getName());
assertEquals(env1, app.getEnvAsMap());
assertEquals(new HashSet<String>(asList("foo=bar", "bar=baz")), new HashSet<String>(app.getEnv()));
Map<String, String> env2 = new HashMap<String, String>();
env2.put("foo", "baz");
env2.put("baz", "bong");
connectedClient.updateApplicationEnv(appName, env2);
app = connectedClient.getApplication(app.getName());
assertEquals(env2, app.getEnvAsMap());
assertEquals(new HashSet<String>(asList("foo=baz", "baz=bong")), new HashSet<String>(app.getEnv()));
connectedClient.updateApplicationEnv(appName, new HashMap<String, String>());
app = connectedClient.getApplication(app.getName());
assertTrue(app.getEnv().isEmpty());
assertTrue(app.getEnvAsMap().isEmpty());
}
@Test
public void updateApplicationDisk() throws IOException {
String appName = createSpringTravelApp("updateDisk");
connectedClient.updateApplicationDiskQuota(appName, 2048);
CloudApplication app = connectedClient.getApplication(appName);
assertEquals(2048, app.getDiskQuota());
}
@Test
public void updateApplicationMemory() throws IOException {
String appName = createSpringTravelApp("updateMemory");
connectedClient.updateApplicationMemory(appName, 256);
CloudApplication app = connectedClient.getApplication(appName);
assertEquals(256, app.getMemory());
}
@Test
public void updateApplicationInstances() throws Exception {
String appName = createSpringTravelApp("updateInstances");
CloudApplication app = connectedClient.getApplication(appName);
assertEquals(1, app.getInstances());
connectedClient.updateApplicationInstances(appName, 3);
app = connectedClient.getApplication(appName);
assertEquals(3, app.getInstances());
connectedClient.updateApplicationInstances(appName, 1);
app = connectedClient.getApplication(appName);
assertEquals(1, app.getInstances());
}
@Test
public void updateApplicationUris() throws IOException {
String appName = namespacedAppName("updateUris");
CloudApplication app = createAndUploadAndStartSimpleSpringApp(appName);
List<String> originalUris = app.getUris();
assertEquals(Collections.singletonList(computeAppUrlNoProtocol(appName)), originalUris);
List<String> uris = new ArrayList<String>(app.getUris());
uris.add(computeAppUrlNoProtocol(namespacedAppName("url2")));
connectedClient.updateApplicationUris(appName, uris);
app = connectedClient.getApplication(appName);
List<String> newUris = app.getUris();
assertNotNull(newUris);
assertEquals(uris.size(), newUris.size());
for (String uri : uris) {
assertTrue(newUris.contains(uri));
}
connectedClient.updateApplicationUris(appName, originalUris);
app = connectedClient.getApplication(appName);
assertEquals(originalUris, app.getUris());
}
//
// Advanced Application tests
//
@Test
public void uploadStandaloneApplication() throws IOException {
String appName = namespacedAppName("standalone-ruby");
List<String> uris = new ArrayList<String>();
List<String> services = new ArrayList<String>();
createStandaloneRubyTestApp(appName, uris, services);
connectedClient.startApplication(appName);
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(CloudApplication.AppState.STARTED, app.getState());
assertEquals(uris, app.getUris());
}
@Test
public void uploadStandaloneApplicationWithURLs() throws IOException {
String appName = namespacedAppName("standalone-node");
List<String> uris = new ArrayList<String>();
uris.add(computeAppUrl(appName));
List<String> services = new ArrayList<String>();
Staging staging = new Staging("node app.js", null);
File file = SampleProjects.standaloneNode();
connectedClient.createApplication(appName, staging, 64, uris, services);
connectedClient.uploadApplication(appName, file.getCanonicalPath());
connectedClient.startApplication(appName);
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(CloudApplication.AppState.STARTED, app.getState());
assertEquals(Collections.singletonList(computeAppUrlNoProtocol(appName)), app.getUris());
}
@Test
public void updateStandaloneApplicationCommand() throws IOException {
String appName = namespacedAppName("standalone-ruby");
List<String> uris = new ArrayList<String>();
List<String> services = new ArrayList<String>();
createStandaloneRubyTestApp(appName, uris, services);
connectedClient.startApplication(appName);
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(CloudApplication.AppState.STARTED, app.getState());
assertEquals(uris, app.getUris());
assertEquals("ruby simple.rb", app.getStaging().getCommand());
connectedClient.stopApplication(appName);
Staging newStaging = new Staging("ruby simple.rb test", "https://github.com/cloudfoundry/heroku-buildpack-ruby");
connectedClient.updateApplicationStaging(appName, newStaging);
app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(uris, app.getUris());
assertEquals("ruby simple.rb test", app.getStaging().getCommand());
assertEquals("https://github.com/cloudfoundry/heroku-buildpack-ruby", app.getStaging().getBuildpackUrl());
}
@Test
public void renameApplication() {
String appName = createSpringTravelApp("5");
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(appName, app.getName());
String newName = namespacedAppName("travel_test-6");
connectedClient.rename(appName, newName);
CloudApplication newApp = connectedClient.getApplication(newName);
assertNotNull(newApp);
assertEquals(newName, newApp.getName());
}
@Test
public void createAndReCreateApplication() {
String appName = createSpringTravelApp("A");
assertEquals(1, connectedClient.getApplications().size());
connectedClient.deleteApplication(appName);
appName = createSpringTravelApp("A");
assertEquals(1, connectedClient.getApplications().size());
connectedClient.deleteApplication(appName);
}
@Test
public void getApplicationsMatchGetApplication() {
String appName = createSpringTravelApp("1");
List<CloudApplication> apps = connectedClient.getApplications();
assertEquals(1, apps.size());
CloudApplication app = connectedClient.getApplication(appName);
assertEquals(app.getName(), apps.get(0).getName());
assertEquals(app.getState(), apps.get(0).getState());
assertEquals(app.getInstances(), apps.get(0).getInstances());
assertEquals(app.getMemory(), apps.get(0).getMemory());
assertEquals(app.getMeta().getGuid(), apps.get(0).getMeta().getGuid());
assertEquals(app.getMeta().getCreated(), apps.get(0).getMeta().getCreated());
assertEquals(app.getMeta().getUpdated(), apps.get(0).getMeta().getUpdated());
assertEquals(app.getUris(), apps.get(0).getUris());
}
@Test
public void getApplicationInstances() throws Exception {
String appName = namespacedAppName("instance1");
CloudApplication app = createAndUploadAndStartSimpleSpringApp(appName);
assertEquals(1, app.getInstances());
boolean passSingleInstance = getInstanceInfosWithTimeout(appName, 1, true);
assertTrue("Couldn't get the right application state in 50 tries", passSingleInstance);
boolean passSingleMultipleInstances = getInstanceInfosWithTimeout(appName, 3, true);
assertTrue("Couldn't get the right application state in 50 tries", passSingleMultipleInstances);
connectedClient.stopApplication(appName);
InstancesInfo instInfo = connectedClient.getApplicationInstances(appName);
assertNull(instInfo);
}
@Test
@Ignore("Ignore until the Java buildpack detects app crashes upon OOM correctly")
public void getCrashes() throws IOException, InterruptedException {
String appName = namespacedAppName("crashes1");
createAndUploadSimpleSpringApp(appName);
connectedClient.updateApplicationEnv(appName, Collections.singletonMap("crash", "true"));
connectedClient.startApplication(appName);
boolean pass = getInstanceInfosWithTimeout(appName, 1, false);
assertTrue("Couldn't get the right application state in 50 tries", pass);
CrashesInfo crashes = connectedClient.getCrashes(appName);
assertNotNull(crashes);
assertTrue(!crashes.getCrashes().isEmpty());
for (CrashInfo info : crashes.getCrashes()) {
assertNotNull(info.getInstance());
assertNotNull(info.getSince());
}
}
@Test
public void accessRandomApplicationUrl() throws Exception {
String appName = UUID.randomUUID().toString();
CloudApplication app = createAndUploadAndStartSimpleSpringApp(appName);
connectedClient.startApplication(appName);
assertEquals(1, app.getInstances());
for (int i = 0; i < 100 && app.getRunningInstances() < 1; i++) {
Thread.sleep(1000);
app = connectedClient.getApplication(appName);
}
assertEquals(1, app.getRunningInstances());
RestUtil restUtil = new RestUtil();
RestTemplate rest = restUtil.createRestTemplate(httpProxyConfiguration, false);
String results = rest.getForObject("http://" + app.getUris().get(0), String.class);
assertTrue(results.contains("Hello world!"));
}
@Test
public void getApplicationStats() throws Exception {
final int instanceCount = 3;
String appName = namespacedAppName("stats2");
createAndUploadSimpleSpringApp(appName);
connectedClient.updateApplicationInstances(appName, instanceCount);
connectedClient.startApplication(appName);
CloudApplication app = connectedClient.getApplication(appName);
assertEquals(CloudApplication.AppState.STARTED, app.getState());
waitForStatsAvailable(appName, instanceCount);
ApplicationStats stats = connectedClient.getApplicationStats(appName);
assertNotNull(stats);
assertNotNull(stats.getRecords());
assertEquals(instanceCount, stats.getRecords().size());
for (InstanceStats instanceStats : stats.getRecords()) {
assertNotNull(instanceStats.getUris());
assertNotNull(instanceStats.getHost());
assertTrue(instanceStats.getPort() > 0);
assertTrue(instanceStats.getDiskQuota() > 0);
assertTrue(instanceStats.getMemQuota() > 0);
assertTrue(instanceStats.getFdsQuota() > 0);
assertTrue(instanceStats.getUptime() > 0);
InstanceStats.Usage usage = instanceStats.getUsage();
assertNotNull(usage);
assertTrue(usage.getDisk() > 0);
assertTrue(usage.getMem() > 0);
assertTimeWithinRange("Usage time should be very recent", usage.getTime().getTime(), FIVE_MINUTES);
}
}
private void waitForStatsAvailable(String appName, int instanceCount) throws InterruptedException {
// TODO: Make this pattern reusable
ApplicationStats stats = connectedClient.getApplicationStats(appName);
for (int retries = 0; retries < 10 && stats.getRecords().size() < instanceCount; retries++) {
Thread.sleep(1000);
stats = connectedClient.getApplicationStats(appName);
}
InstanceStats firstInstance = stats.getRecords().get(0);
assertEquals("0", firstInstance.getId());
for (int retries = 0; retries < 50 && firstInstance.getUsage() == null; retries++) {
Thread.sleep(1000);
stats = connectedClient.getApplicationStats(appName);
firstInstance = stats.getRecords().get(0);
}
}
@Test
public void getApplicationStatsStoppedApp() throws IOException {
String appName = namespacedAppName("stats2");
createAndUploadAndStartSimpleSpringApp(appName);
connectedClient.stopApplication(appName);
ApplicationStats stats = connectedClient.getApplicationStats(appName);
assertTrue(stats.getRecords().isEmpty());
}
@Test
public void uploadAppWithNonUnsubscribingCallback() throws IOException {
String appName = namespacedAppName("upload-non-unsubscribing-callback");
createSpringApplication(appName);
File file = SampleProjects.springTravel();
NonUnsubscribingUploadStatusCallback callback = new NonUnsubscribingUploadStatusCallback();
connectedClient.uploadApplication(appName, file, callback);
CloudApplication env = connectedClient.getApplication(appName);
assertEquals(CloudApplication.AppState.STOPPED, env.getState());
assertTrue(callback.progressCount > 1); // must have taken at least 10 seconds
}
@Test
public void uploadAppWithUnsubscribingCallback() throws IOException {
String appName = namespacedAppName("upload-unsubscribing-callback");
createSpringApplication(appName);
File file = SampleProjects.springTravel();
UnsubscribingUploadStatusCallback callback = new UnsubscribingUploadStatusCallback();
connectedClient.uploadApplication(appName, file, callback);
CloudApplication env = connectedClient.getApplication(appName);
assertEquals(CloudApplication.AppState.STOPPED, env.getState());
assertTrue(callback.progressCount == 1);
}
@Test
public void uploadSinatraApp() throws IOException {
String appName = namespacedAppName("env");
ClassPathResource cpr = new ClassPathResource("apps/env/");
File explodedDir = cpr.getFile();
Staging staging = new Staging();
createAndUploadExplodedTestApp(appName, explodedDir, staging);
connectedClient.startApplication(appName);
CloudApplication env = connectedClient.getApplication(appName);
assertEquals(CloudApplication.AppState.STARTED, env.getState());
}
@Test
public void uploadAppWithNonAsciiFileName() throws IOException {
String appName = namespacedAppName("non-ascii");
List<String> uris = new ArrayList<String>();
uris.add(computeAppUrl(appName));
File war = SampleProjects.nonAsciFileName();
List<String> serviceNames = new ArrayList<String>();
connectedClient.createApplication(appName, new Staging(),
DEFAULT_MEMORY, uris, serviceNames);
connectedClient.uploadApplication(appName, war.getCanonicalPath());
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(CloudApplication.AppState.STOPPED, app.getState());
connectedClient.startApplication(appName);
app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(CloudApplication.AppState.STARTED, app.getState());
connectedClient.deleteApplication(appName);
}
@Test
public void startExplodedApplication() throws IOException {
String appName = namespacedAppName("exploded_app");
createAndUploadExplodedSpringTestApp(appName);
connectedClient.startApplication(appName);
CloudApplication app = connectedClient.getApplication(appName);
assertEquals(CloudApplication.AppState.STARTED, app.getState());
}
@Test
public void getStacks() throws Exception {
List<CloudStack> stacks = connectedClient.getStacks();
assert(stacks.size() >= 1);
CloudStack stack = null;
for (CloudStack s : stacks) {
if (DEFAULT_STACK_NAME.equals(s.getName())) {
stack = s;
}
}
assertNotNull(stack);
assertNotNull(stack.getMeta().getGuid());
assertEquals(DEFAULT_STACK_NAME, stack.getName());
assertNotNull(stack.getDescription());
}
@Test
public void getStack() throws Exception {
CloudStack stack = connectedClient.getStack(DEFAULT_STACK_NAME);
assertNotNull(stack);
assertNotNull(stack.getMeta().getGuid());
assertEquals(DEFAULT_STACK_NAME, stack.getName());
assertNotNull(stack.getDescription());
}
//
// Files and Log tests
//
@Test
public void getLogs() throws Exception {
String appName = namespacedAppName("simple_logs");
createAndUploadAndStartSimpleSpringApp(appName);
boolean pass = getInstanceInfosWithTimeout(appName, 1, true);
assertTrue("Couldn't get the right application state", pass);
Thread.sleep(10000); // let's have some time to get some logs generated
Map<String, String> logs = connectedClient.getLogs(appName);
assertNotNull(logs);
assertTrue(logs.size() > 0);
}
@Test
public void streamLogs() throws Exception {
// disable proxy validation for this test, since Loggregator websockets
// connectivity does not currently support proxies
new SocketDestHelper().setAllowedOnCurrentThread();
String appName = namespacedAppName("simple_logs");
CloudApplication app = createAndUploadAndStartSimpleSpringApp(appName);
boolean pass = getInstanceInfosWithTimeout(appName, 1, true);
assertTrue("Couldn't get the right application state", pass);
List<ApplicationLog> logs = doGetRecentLogs(appName);
for (int index = 0; index < logs.size() - 1; index++) {
int comparison = logs.get(index).getTimestamp().compareTo(logs.get(index + 1).getTimestamp());
assertTrue("Logs are not properly sorted", comparison <= 0);
}
AccumulatingApplicationLogListener testListener = new AccumulatingApplicationLogListener();
connectedClient.streamLogs(appName, testListener);
String appUri = "http://" + app.getUris().get(0);
RestTemplate appTemplate = new RestTemplate();
int attempt = 0;
do {
// no need to sleep, visiting the app uri should be sufficient
try {
appTemplate.getForObject(appUri, String.class);
} catch (HttpClientErrorException ex) {
// ignore
}
if (testListener.logs.size() > 0) {
break;
}
Thread.sleep(1000);
} while (attempt++ < 30);
assertTrue("Failed to stream normal log", testListener.logs.size() > 0);
}
private List<ApplicationLog> doGetRecentLogs(String appName) throws InterruptedException {
int attempt = 0;
do {
List<ApplicationLog> logs = connectedClient.getRecentLogs(appName);
if (logs.size() > 0) {
return logs;
}
Thread.sleep(1000);
} while (attempt++ < 20);
fail("Failed to see recent logs");
return null;
}
@Test
@Ignore("Ignore until the Java buildpack detects app crashes upon OOM correctly")
public void getCrashLogs() throws Exception {
String appName = namespacedAppName("simple_crashlogs");
createAndUploadSimpleSpringApp(appName);
connectedClient.updateApplicationEnv(appName, Collections.singletonMap("crash", "true"));
connectedClient.startApplication(appName);
boolean pass = getInstanceInfosWithTimeout(appName, 1, false);
assertTrue("Couldn't get the right application state in 50 tries", pass);
Map<String, String> logs = connectedClient.getCrashLogs(appName);
assertNotNull(logs);
assertTrue(logs.size() > 0);
for (String log : logs.keySet()) {
assertNotNull(logs.get(log));
}
}
@Test
public void getFile() throws Exception {
String appName = namespacedAppName("simple_getFile");
createAndUploadAndStartSimpleSpringApp(appName);
boolean running = getInstanceInfosWithTimeout(appName, 1, true);
assertTrue("App failed to start", running);
doGetFile(connectedClient, appName);
}
@Test
public void openFile() throws Exception {
String appName = namespacedAppName("simple_openFile");
createAndUploadAndStartSimpleSpringApp(appName);
boolean running = getInstanceInfosWithTimeout(appName, 1, true);
assertTrue("App failed to start", running);
doOpenFile(connectedClient, appName);
}
//
// Basic Services tests
//
@Test
public void getServiceOfferings() {
List<CloudServiceOffering> offerings = connectedClient.getServiceOfferings();
assertNotNull(offerings);
assertTrue(offerings.size() >= 2);
CloudServiceOffering offering = null;
for (CloudServiceOffering so : offerings) {
if (so.getLabel().equals(MYSQL_SERVICE_LABEL)) {
offering = so;
break;
}
}
assertNotNull(offering);
assertEquals(MYSQL_SERVICE_LABEL, offering.getLabel());
assertNotNull(offering.getCloudServicePlans());
assertTrue(offering.getCloudServicePlans().size() > 0);
assertNotNull(offering.getName());
assertNotNull(offering.getDescription());
assertNotNull(offering.getLabel());
assertNotNull(offering.getUniqueId());
assertNotNull(offering.getExtra());
CloudServicePlan plan = offering.getCloudServicePlans().get(0);
assertNotNull(plan.getName());
assertNotNull(plan.getUniqueId());
assertNotNull(plan.getDescription());
assertSame(offering, plan.getServiceOffering());
}
@Test
public void getCreateDeleteService() throws MalformedURLException {
String serviceName = "mysql-test";
createMySqlService(serviceName);
CloudService service = connectedClient.getService(serviceName);
assertNotNull(service);
assertEquals(serviceName, service.getName());
assertTimeWithinRange("Creation time should be very recent",
service.getMeta().getCreated().getTime(), FIVE_MINUTES);
connectedClient.deleteService(serviceName);
List<CloudService> services = connectedClient.getServices();
assertNotNull(services);
assertEquals(0, services.size());
}
@Test
public void getServices() {
List<CloudService> expectedServices = Arrays.asList(
createMySqlService("mysql-test"),
createUserProvidedService("user-provided-test"),
createMySqlService("mysql-test2")
);
List<CloudService> services = connectedClient.getServices();
assertNotNull(services);
assertEquals(3, services.size());
for (CloudService expectedService : expectedServices) {
assertServiceMatching(expectedService, services);
}
}
@Test
public void getServiceBrokers() {
assumeTrue(CCNG_USER_IS_ADMIN);
List<CloudServiceBroker> brokers = connectedClient.getServiceBrokers();
assertNotNull(brokers);
assertTrue(brokers.size() >= 1);
CloudServiceBroker broker0 = brokers.get(0);
assertNotNull(broker0.getMeta());
assertNotNull(broker0.getName());
assertNotNull(broker0.getUrl());
assertNotNull(broker0.getUsername());
}
@Test
public void serviceBrokerLifecycle() throws IOException {
assumeTrue(CCNG_USER_IS_ADMIN);
createAndUploadAndStartSampleServiceBrokerApp("haash-broker");
boolean pass = ensureApplicationRunning("haash-broker");
assertTrue("haash-broker failed to start", pass);
CloudServiceBroker newBroker = new CloudServiceBroker(CloudEntity.Meta.defaultMeta(), "haash-broker", "http://haash-broker.cf.deepsouthcloud.com", "warreng", "snoopdogg");
connectedClient.createServiceBroker(newBroker);
CloudServiceBroker broker = connectedClient.getServiceBroker("haash-broker");
assertNotNull(broker);
assertNotNull(broker.getMeta());
assertEquals("haash-broker", broker.getName());
assertEquals("http://haash-broker.cf.deepsouthcloud.com", broker.getUrl());
assertEquals("warreng", broker.getUsername());
assertNull(broker.getPassword());
newBroker = new CloudServiceBroker(CloudEntity.Meta.defaultMeta(), "haash-broker", "http://haash-broker.cf.deepsouthcloud.com", "warreng", "snoopdogg");
connectedClient.updateServiceBroker(newBroker);
connectedClient.updateServicePlanVisibilityForBroker("haash-broker", true);
connectedClient.updateServicePlanVisibilityForBroker("haash-broker", false);
connectedClient.deleteServiceBroker("haash-broker");
}
private boolean ensureApplicationRunning(String appName) {
InstancesInfo instances;
boolean pass = false;
for (int i = 0; i < 50; i++) {
try {
instances = getInstancesWithTimeout(connectedClient, appName);
assertNotNull(instances);
List<InstanceInfo> infos = instances.getInstances();
assertEquals(1, infos.size());
int passCount = 0;
for (InstanceInfo info : infos) {
if (InstanceState.RUNNING.equals(info.getState())) {
passCount++;
}
}
if (passCount == infos.size()) {
pass = true;
break;
}
} catch (CloudFoundryException ex) {
// ignore (we may get this when staging is still ongoing)
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// ignore
}
}
return pass;
}
/*@Test
public void getServiceBroker() {
assumeTrue(CCNG_USER_IS_ADMIN);
CloudServiceBroker broker = connectedClient.getServiceBroker("haash-broker");
assertNotNull(broker);
assertNotNull(broker.getMeta());
assertEquals("haash-broker", broker.getName());
assertEquals("http://haash-broker.cf.deepsouthcloud.com", broker.getUrl());
assertEquals("warreng", broker.getUsername());
assertNull(broker.getPassword());
}
@Test
public void createServiceBroker() {
assumeTrue(CCNG_USER_IS_ADMIN);
CloudServiceBroker newBroker = new CloudServiceBroker(CloudEntity.Meta.defaultMeta(), "haash-broker", "http://haash-broker.cf.deepsouthcloud.com", "warreng", "natedogg");
connectedClient.createServiceBroker(newBroker);
}
@Test
public void updateServiceBroker() {
assumeTrue(CCNG_USER_IS_ADMIN);
CloudServiceBroker newBroker = new CloudServiceBroker(CloudEntity.Meta.defaultMeta(), "haash-broker", "http://haash-broker.cf.deepsouthcloud.com", "warreng", "snoopdogg");
connectedClient.updateServiceBroker(newBroker);
}*/
private void assertServiceMatching(CloudService expectedService, List<CloudService> services) {
for (CloudService service : services) {
if (service.getName().equals(expectedService.getName())) {
assertServicesEqual(expectedService, service);
return;
}
}
fail("No service found matching " + expectedService.getName());
}
@Test
public void getService() {
String serviceName = "mysql-test";
CloudService expectedService = createMySqlService(serviceName);
CloudService service = connectedClient.getService(serviceName);
assertNotNull(service);
assertServicesEqual(expectedService, service);
}
@Test
public void getServiceWithVersionAndProvider() {
String serviceName = "mysql-test-version-provider";
CloudService expectedService = createMySqlServiceWithVersionAndProvider(serviceName);
CloudService service = connectedClient.getService(serviceName);
assertNotNull(service);
assertServicesEqual(expectedService, service);
assertEquals(expectedService.getProvider(), service.getProvider());
assertEquals(expectedService.getVersion(), service.getVersion());
}
@Test
public void getUserProvidedService() {
String serviceName = "user-provided-test-service";
CloudService expectedService = createUserProvidedService(serviceName);
CloudService service = connectedClient.getService(serviceName);
assertNotNull(service);
assertServicesEqual(expectedService, service);
}
private void assertServicesEqual(CloudService expectedService, CloudService service) {
assertEquals(expectedService.getName(), service.getName());
assertEquals(expectedService.getLabel(), service.getLabel());
assertEquals(expectedService.getPlan(), service.getPlan());
assertEquals(expectedService.isUserProvided(), service.isUserProvided());
}
//
// Application and Services tests
//
@Test
public void createApplicationWithService() throws IOException {
String serviceName = "test_database";
String appName = createSpringTravelApp("application-with-services", Collections.singletonList(serviceName));
uploadSpringTravelApp(appName);
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app);
assertEquals(appName, app.getName());
assertNotNull(app.getServices());
assertEquals(1, app.getServices().size());
assertEquals(serviceName, app.getServices().get(0));
}
@Test
public void deleteServiceThatIsBoundToApp() throws MalformedURLException {
String serviceName = "mysql-del-svc";
String appName = createSpringTravelApp("del-svc", Collections.singletonList(serviceName));
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app.getServices());
assertEquals(1, app.getServices().size());
assertEquals(serviceName, app.getServices().get(0));
connectedClient.deleteService(serviceName);
}
@Test
public void updateApplicationService() throws IOException {
String serviceName = "test_database";
createMySqlService(serviceName);
String appName = createSpringTravelApp("7");
connectedClient.updateApplicationServices(appName, Collections.singletonList(serviceName));
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app.getServices());
assertTrue(app.getServices().size() > 0);
assertEquals(serviceName, app.getServices().get(0));
List<String> emptyList = Collections.emptyList();
connectedClient.updateApplicationServices(appName, emptyList);
app = connectedClient.getApplication(appName);
assertNotNull(app.getServices());
assertEquals(emptyList, app.getServices());
}
@Test
public void bindAndUnbindService() throws IOException {
String serviceName = "test_database";
createMySqlService(serviceName);
String appName = createSpringTravelApp("bind1");
CloudApplication app = connectedClient.getApplication(appName);
assertNotNull(app.getServices());
assertTrue(app.getServices().isEmpty());
connectedClient.bindService(appName, serviceName);
app = connectedClient.getApplication(appName);
assertNotNull(app.getServices());
assertEquals(1, app.getServices().size());
assertEquals(serviceName, app.getServices().get(0));
connectedClient.unbindService(appName, serviceName);
app = connectedClient.getApplication(appName);
assertNotNull(app.getServices());
assertTrue(app.getServices().isEmpty());
}
@Test
public void defaultDomainFound() throws Exception {
assertNotNull(connectedClient.getDefaultDomain());
}
@Test
public void getDomains() {
connectedClient.addDomain(TEST_DOMAIN);
List<CloudDomain> allDomains = connectedClient.getDomains();
assertNotNull(getDomainNamed(defaultDomainName, allDomains));
assertNotNull(getDomainNamed(TEST_DOMAIN, allDomains));
}
@Test
public void addAndDeleteDomain() {
connectedClient.addDomain(TEST_DOMAIN);
assertDomainInList(connectedClient.getPrivateDomains());
assertDomainInList(connectedClient.getDomainsForOrg());
assertDomainNotInList(connectedClient.getSharedDomains());
connectedClient.deleteDomain(TEST_DOMAIN);
assertDomainNotInList(connectedClient.getPrivateDomains());
assertDomainNotInList(connectedClient.getDomainsForOrg());
}
private void assertDomainInList(List<CloudDomain> domains) {
assertTrue(domains.size() >= 1);
assertNotNull(getDomainNamed(TEST_DOMAIN, domains));
}
private void assertDomainNotInList(List<CloudDomain> domains) {
assertNull(getDomainNamed(TEST_DOMAIN, domains));
}
@Test
public void addAndDeleteRoute() {
connectedClient.addDomain(TEST_DOMAIN);
connectedClient.addRoute("my_route1", TEST_DOMAIN);
connectedClient.addRoute("my_route2", TEST_DOMAIN);
List<CloudRoute> routes = connectedClient.getRoutes(TEST_DOMAIN);
assertNotNull(getRouteWithHost("my_route1", routes));
assertNotNull(getRouteWithHost("my_route2", routes));
connectedClient.deleteRoute("my_route2", TEST_DOMAIN);
routes = connectedClient.getRoutes(TEST_DOMAIN);
assertNotNull(getRouteWithHost("my_route1", routes));
assertNull(getRouteWithHost("my_route2", routes));
// test that removing domain that has routes throws exception
try {
connectedClient.deleteDomain(TEST_DOMAIN);
fail("should have thrown exception");
}
catch (IllegalStateException ex) {
assertTrue(ex.getMessage().contains("in use"));
}
}
@Test
public void deleteOrphanedRoutes() {
connectedClient.addDomain(TEST_DOMAIN);
connectedClient.addRoute("unbound_route", TEST_DOMAIN);
List<CloudRoute> routes = connectedClient.getRoutes(TEST_DOMAIN);
CloudRoute unboundRoute = getRouteWithHost("unbound_route", routes);
assertNotNull(unboundRoute);
assertEquals(0, unboundRoute.getAppsUsingRoute());
List<CloudRoute> deletedRoutes = connectedClient.deleteOrphanedRoutes();
assertNull(getRouteWithHost("unbound_route", connectedClient.getRoutes(TEST_DOMAIN)));
assertTrue(deletedRoutes.size() > 0);
boolean found = false;
for (CloudRoute route : deletedRoutes) {
if (route.getHost().equals("unbound_route")) {
found = true;
}
}
assertTrue(found);
}
@Test
public void appsWithRoutesAreCounted() throws IOException {
String appName = namespacedAppName("my_route3");
CloudApplication app = createAndUploadSimpleTestApp(appName);
List<String> uris = app.getUris();
uris.add("my_route3." + TEST_DOMAIN);
connectedClient.addDomain(TEST_DOMAIN);
connectedClient.updateApplicationUris(appName, uris);
List<CloudRoute> routes = connectedClient.getRoutes(TEST_DOMAIN);
assertNotNull(getRouteWithHost("my_route3", routes));
assertEquals(1, getRouteWithHost("my_route3", routes).getAppsUsingRoute());
assertTrue(getRouteWithHost("my_route3", routes).inUse());
List<CloudRoute> defaultDomainRoutes = connectedClient.getRoutes(defaultDomainName);
assertNotNull(getRouteWithHost(appName, defaultDomainRoutes));
assertEquals(1, getRouteWithHost(appName, defaultDomainRoutes).getAppsUsingRoute());
assertTrue(getRouteWithHost(appName, defaultDomainRoutes).inUse());
}
//
// Configuration/Metadata tests
//
@Test
public void infoAvailableWithoutLoggingIn() throws Exception {
CloudFoundryClient infoClient = new CloudFoundryClient(new URL(CCNG_API_URL), httpProxyConfiguration, CCNG_API_SSL);
CloudInfo info = infoClient.getCloudInfo();
assertNotNull(info.getName());
assertNotNull(info.getSupport());
assertNotNull(info.getBuild());
assertTrue(info.getUser() == null);
}
@Test
public void infoForUserAvailable() throws Exception {
CloudInfo info = connectedClient.getCloudInfo();
assertNotNull(info.getName());
assertNotNull(info.getSupport());
assertNotNull(info.getBuild());
assertNotNull(info.getSupport());
assertNotNull(info.getSupport());
assertEquals(CCNG_USER_EMAIL, info.getUser());
assertNotNull(info.getLimits());
// Just ensure that we got back some sensible values
assertTrue(info.getLimits().getMaxApps() > 0 && info.getLimits().getMaxApps() < 1000);
assertTrue(info.getLimits().getMaxServices() > 0 && info.getLimits().getMaxServices() < 1000);
assertTrue(info.getLimits().getMaxTotalMemory() > 0 && info.getLimits().getMaxTotalMemory() < 100000);
assertTrue(info.getLimits().getMaxUrisPerApp() > 0 && info.getLimits().getMaxUrisPerApp() < 100);
}
@Test
public void updatePassword() throws MalformedURLException {
// Not working currently
assumeTrue(false);
String newPassword = "newPass123";
connectedClient.updatePassword(newPassword);
CloudFoundryClient clientWithChangedPassword =
new CloudFoundryClient(new CloudCredentials(CCNG_USER_EMAIL, newPassword), new URL(CCNG_API_URL), httpProxyConfiguration);
clientWithChangedPassword.login();
// Revert
connectedClient.updatePassword(CCNG_USER_PASS);
connectedClient.login();
}
@Test
@Ignore("This test takes, by design, at least 10 minutes. Enable this only when dealing with authentication issues "
+ "or a change in the client side OAuth implementation")
public void dealingWithExpiredToken() throws Exception {
// The current token expiration time is 10 minutes. If we can still make authenticated calls past that,
// then the transparent token refresh scheme working as expected.
for (int i = 0; i < 30; i++) {
System.out.println("Elapsed time since the last login (at least) " + i/2 + " minutes");
getServiceOfferings();
Thread.sleep(30 * 1000);
}
}
@Test
public void getRestLog() throws IOException {
final List<RestLogEntry> log1 = new ArrayList<RestLogEntry>();
final List<RestLogEntry> log2 = new ArrayList<RestLogEntry>();
connectedClient.registerRestLogListener(new RestLogCallback() {
public void onNewLogEntry(RestLogEntry logEntry) {
log1.add(logEntry);
}
});
RestLogCallback callback2 = new RestLogCallback() {
public void onNewLogEntry(RestLogEntry logEntry) {
log2.add(logEntry);
}
};
connectedClient.registerRestLogListener(callback2);
getApplications();
connectedClient.deleteAllApplications();
connectedClient.deleteAllServices();
assertTrue(log1.size() > 0);
assertEquals(log1, log2);
connectedClient.unRegisterRestLogListener(callback2);
getApplications();
connectedClient.deleteAllApplications();
assertTrue(log1.size() > log2.size());
}
@Test
public void getStagingLogs() throws Exception {
String appName = createSpringTravelApp("stagingLogs");
File file = SampleProjects.springTravel();
connectedClient.uploadApplication(appName, file.getCanonicalPath());
StartingInfo startingInfo;
String firstLine = null;
int i = 0;
do {
startingInfo = connectedClient.startApplication(appName);
if (startingInfo != null && startingInfo.getStagingFile() != null) {
int offset = 0;
firstLine = connectedClient
.getStagingLogs(startingInfo, offset);
}
if (startingInfo != null && startingInfo.getStagingFile() != null
&& firstLine != null) {
break;
} else {
connectedClient.stopApplication(appName);
Thread.sleep(10000);
}
} while (++i < 5);
assertNotNull(startingInfo);
assertNotNull(startingInfo.getStagingFile());
assertNotNull(firstLine);
assertTrue(firstLine.length() > 0);
}
@Test
public void quotasAvailable() throws Exception {
List<CloudQuota> quotas = connectedClient.getQuotas();
assertNotNull(quotas);
assertTrue(quotas.size() > 0);
}
@Test
public void CRUDQuota() throws Exception {
assumeTrue(CCNG_USER_IS_ADMIN);
// create quota
CloudQuota cloudQuota = new CloudQuota(null, CCNG_QUOTA_NAME_TEST);
connectedClient.createQuota(cloudQuota);
CloudQuota afterCreate = connectedClient.getQuotaByName(CCNG_QUOTA_NAME_TEST, true);
assertNotNull(afterCreate);
// change quota mem to 10240
afterCreate.setMemoryLimit(10240);
connectedClient.updateQuota(afterCreate, CCNG_QUOTA_NAME_TEST);
CloudQuota afterUpdate = connectedClient.getQuotaByName(CCNG_QUOTA_NAME_TEST, true);
assertEquals(10240, afterUpdate.getMemoryLimit());
// delete the quota
connectedClient.deleteQuota(CCNG_QUOTA_NAME_TEST);
CloudQuota afterDelete = connectedClient.getQuotaByName(CCNG_QUOTA_NAME_TEST, false);
assertNull(afterDelete);
}
@Test
public void setQuotaToOrg() throws Exception {
assumeTrue(CCNG_USER_IS_ADMIN);
// get old quota to restore after test
CloudOrganization org = connectedClient.getOrgByName(CCNG_USER_ORG, true);
CloudQuota oldQuota = org.getQuota();
// create and set test_quota to org
CloudQuota cloudQuota = new CloudQuota(null, CCNG_QUOTA_NAME_TEST);
connectedClient.createQuota(cloudQuota);
connectedClient.setQuotaToOrg(CCNG_USER_ORG, CCNG_QUOTA_NAME_TEST);
// get the bound quota of org
org = connectedClient.getOrgByName(CCNG_USER_ORG, true);
CloudQuota newQuota = org.getQuota();
// bound quota should be equals to test_quota
assertEquals(CCNG_QUOTA_NAME_TEST, newQuota.getName());
// restore org to default quota
connectedClient.setQuotaToOrg(CCNG_USER_ORG, oldQuota.getName());
connectedClient.deleteQuota(CCNG_QUOTA_NAME_TEST);
}
//
// Shared test methods
//
private boolean getInstanceInfosWithTimeout(String appName, int count, boolean shouldBeRunning) {
if (count > 1) {
connectedClient.updateApplicationInstances(appName, count);
CloudApplication app = connectedClient.getApplication(appName);
assertEquals(count, app.getInstances());
}
InstancesInfo instances;
boolean pass = false;
for (int i = 0; i < 50; i++) {
try {
instances = getInstancesWithTimeout(connectedClient, appName);
assertNotNull(instances);
List<InstanceInfo> infos = instances.getInstances();
assertEquals(count, infos.size());
int passCount = 0;
for (InstanceInfo info : infos) {
if (shouldBeRunning) {
if (InstanceState.RUNNING.equals(info.getState()) ||
InstanceState.STARTING.equals(info.getState())) {
passCount++;
}
} else {
if (InstanceState.CRASHED.equals(info.getState()) ||
InstanceState.FLAPPING.equals(info.getState())) {
passCount++;
}
}
}
if (passCount == infos.size()) {
pass = true;
break;
}
} catch (CloudFoundryException ex) {
// ignore (we may get this when staging is still ongoing)
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// ignore
}
}
return pass;
}
private void doOpenFile(CloudFoundryClient client, String appName) throws Exception {
String appDir = "app";
String fileName = appDir + "/WEB-INF/web.xml";
String emptyPropertiesFileName = appDir + "/WEB-INF/classes/empty.properties";
// File is often not available immediately after starting an app... so
// allow up to 60 seconds wait
for (int i = 0; i < 60; i++) {
try {
client.getFile(appName, 0, fileName);
break;
} catch (HttpServerErrorException ex) {
Thread.sleep(1000);
}
}
// Test open file
client.openFile(appName, 0, fileName, new ClientHttpResponseCallback() {
public void onClientHttpResponse(ClientHttpResponse clientHttpResponse) throws IOException {
InputStream in = clientHttpResponse.getBody();
assertNotNull(in);
byte[] fileContents = IOUtils.toByteArray(in);
assertTrue(fileContents.length > 5);
}
});
client.openFile(appName, 0, emptyPropertiesFileName, new ClientHttpResponseCallback() {
public void onClientHttpResponse(ClientHttpResponse clientHttpResponse) throws IOException {
InputStream in = clientHttpResponse.getBody();
assertNotNull(in);
byte[] fileContents = IOUtils.toByteArray(in);
assertTrue(fileContents.length == 0);
}
});
}
private void doGetFile(CloudFoundryClient client, String appName) throws Exception {
String appDir = "app";
String fileName = appDir + "/WEB-INF/web.xml";
String emptyPropertiesFileName = appDir + "/WEB-INF/classes/empty.properties";
// File is often not available immediately after starting an app... so allow up to 60 seconds wait
for (int i = 0; i < 60; i++) {
try {
client.getFile(appName, 0, fileName);
break;
} catch (HttpServerErrorException ex) {
Thread.sleep(1000);
}
}
// Test downloading full file
String fileContent = client.getFile(appName, 0, fileName);
assertNotNull(fileContent);
assertTrue(fileContent.length() > 5);
// Test downloading range of file with start and end position
int end = fileContent.length() - 3;
int start = end/2;
String fileContent2 = client.getFile(appName, 0, fileName, start, end);
assertEquals(fileContent.substring(start, end), fileContent2);
// Test downloading range of file with just start position
String fileContent3 = client.getFile(appName, 0, fileName, start);
assertEquals(fileContent.substring(start), fileContent3);
// Test downloading range of file with start position and end position exceeding the length
int positionPastEndPosition = fileContent.length() + 999;
String fileContent4 = client.getFile(appName, 0, fileName, start, positionPastEndPosition);
assertEquals(fileContent.substring(start), fileContent4);
// Test downloading end portion of file with length
int length = fileContent.length() / 2;
String fileContent5 = client.getFileTail(appName, 0, fileName, length);
assertEquals(fileContent.substring(fileContent.length() - length), fileContent5);
// Test downloading one byte of file with start and end position
String fileContent6 = client.getFile(appName, 0, fileName, start, start + 1);
assertEquals(fileContent.substring(start, start + 1), fileContent6);
assertEquals(1, fileContent6.length());
// Test downloading range of file with invalid start position
int invalidStartPosition = fileContent.length() + 999;
try {
client.getFile(appName, 0, fileName, invalidStartPosition);
fail("should have thrown exception");
} catch (CloudFoundryException e) {
assertTrue(e.getStatusCode().equals(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE));
}
// Test downloading empty file
String fileContent7 = client.getFile(appName, 0, emptyPropertiesFileName);
assertNull(fileContent7);
// Test downloading with invalid parameters - should all throw exceptions
try {
client.getFile(appName, 0, fileName, -2);
fail("should have thrown exception");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("start position"));
}
try {
client.getFile(appName, 0, fileName, 10, -2);
fail("should have thrown exception");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("end position"));
}
try {
client.getFile(appName, 0, fileName, 29, 28);
fail("should have thrown exception");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("end position"));
}
try {
client.getFile(appName, 0, fileName, 29, 28);
fail("should have thrown exception");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("29"));
}
try {
client.getFileTail(appName, 0, fileName, 0);
fail("should have thrown exception");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("length"));
}
}
//
// Helper methods
//
private CloudApplication createAndUploadSimpleTestApp(String name) throws IOException {
createAndUploadSimpleSpringApp(name);
return connectedClient.getApplication(name);
}
private String namespacedAppName(String basename) {
return TEST_NAMESPACE + "-" + basename;
}
private static String defaultNamespace(String email) {
String s;
if(email.contains("@")) {
s = email.substring(0, email.indexOf('@'));
} else {
s = email;
}
return s.replaceAll("\\.", "-").replaceAll("\\+", "-");
}
//
// helper methods
//
private String createSpringTravelApp(String suffix) {
return createSpringTravelApp(suffix, null);
}
private String createSpringTravelApp(String suffix, List<String> serviceNames) {
String appName = namespacedAppName("travel_test-" + suffix);
createSpringApplication(appName, serviceNames);
return appName;
}
private CloudApplication uploadSpringTravelApp(String appName) throws IOException {
File file = SampleProjects.springTravel();
connectedClient.uploadApplication(appName, file.getCanonicalPath());
return connectedClient.getApplication(appName);
}
private CloudApplication createAndUploadExplodedSpringTestApp(String appName)
throws IOException {
File explodedDir = SampleProjects.springTravelUnpacked(temporaryFolder);
assertTrue("Expected exploded test app at " + explodedDir.getCanonicalPath(), explodedDir.exists());
createTestApp(appName, null, new Staging());
connectedClient.uploadApplication(appName, explodedDir.getCanonicalPath());
return connectedClient.getApplication(appName);
}
private CloudApplication createAndUploadAndStartSampleServiceBrokerApp(String appName) throws IOException {
createSpringApplication(appName);
File jar = SampleProjects.sampleServiceBrokerApp();
connectedClient.uploadApplication(appName, jar.getCanonicalPath());
connectedClient.startApplication(appName);
return connectedClient.getApplication(appName);
}
private CloudApplication createAndUploadAndStartSimpleSpringApp(String appName) throws IOException {
createAndUploadSimpleSpringApp(appName);
connectedClient.startApplication(appName);
return connectedClient.getApplication(appName);
}
private CloudApplication createAndUploadSimpleSpringApp(String appName) throws IOException {
createSpringApplication(appName);
File war = SampleProjects.simpleSpringApp();
connectedClient.uploadApplication(appName, war.getCanonicalPath());
return connectedClient.getApplication(appName);
}
private CloudApplication createAndUploadExplodedTestApp(String appName, File explodedDir, Staging staging)
throws IOException {
assertTrue("Expected exploded test app at " + explodedDir.getCanonicalPath(), explodedDir.exists());
createTestApp(appName, null, staging);
connectedClient.uploadApplication(appName, explodedDir.getCanonicalPath());
return connectedClient.getApplication(appName);
}
private void createStandaloneRubyTestApp(String appName, List<String> uris, List<String> services) throws IOException {
Staging staging = new Staging("ruby simple.rb", null);
File file = SampleProjects.standaloneRuby();
connectedClient.createApplication(appName, staging, 128, uris, services);
connectedClient.uploadApplication(appName, file.getCanonicalPath());
}
private void createSpringApplication(String appName) {
createTestApp(appName, null, new Staging());
}
private void createSpringApplication(String appName, List<String> serviceNames) {
createTestApp(appName, serviceNames, new Staging());
}
private void createSpringApplication(String appName, String buildpackUrl) {
createTestApp(appName, null, new Staging(null, buildpackUrl));
}
private void createSpringApplication(String appName, String stack, Integer healthCheckTimeout) {
createTestApp(appName, null, new Staging(null, null, stack, healthCheckTimeout));
}
private void createTestApp(String appName, List<String> serviceNames, Staging staging) {
List<String> uris = new ArrayList<String>();
uris.add(computeAppUrl(appName));
if (serviceNames != null) {
for (String serviceName : serviceNames) {
createMySqlService(serviceName);
}
}
connectedClient.createApplication(appName, staging,
DEFAULT_MEMORY,
uris, serviceNames);
}
private CloudService createMySqlServiceWithVersionAndProvider(String serviceName) {
CloudServiceOffering databaseServiceOffering = getCloudServiceOffering(MYSQL_SERVICE_LABEL);
CloudService service = new CloudService(CloudEntity.Meta.defaultMeta(), serviceName);
service.setProvider(databaseServiceOffering.getProvider());
service.setLabel(databaseServiceOffering.getLabel());
service.setVersion(databaseServiceOffering.getVersion());
service.setPlan(MYSQL_SERVICE_PLAN);
connectedClient.createService(service);
return service;
}
private CloudService createMySqlService(String serviceName) {
CloudService service = new CloudService(CloudEntity.Meta.defaultMeta(), serviceName);
service.setLabel(MYSQL_SERVICE_LABEL);
service.setPlan(MYSQL_SERVICE_PLAN);
connectedClient.createService(service);
return service;
}
private CloudService createUserProvidedService(String serviceName) {
CloudService service = new CloudService(CloudEntity.Meta.defaultMeta(), serviceName);
Map<String, Object> credentials = new HashMap<String, Object>();
credentials.put("host", "example.com");
credentials.put("port", 1234);
credentials.put("user", "me");
connectedClient.createUserProvidedService(service, credentials);
return service;
}
private CloudServiceOffering getCloudServiceOffering(String label) {
List<CloudServiceOffering> serviceOfferings = connectedClient.getServiceOfferings();
for (CloudServiceOffering so : serviceOfferings) {
if (so.getLabel().equals(label)) {
return so;
}
}
throw new IllegalStateException("No CloudServiceOffering found with label " + label + ".");
}
private InstancesInfo getInstancesWithTimeout(CloudFoundryClient client, String appName) {
long start = System.currentTimeMillis();
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
// ignore
}
final InstancesInfo applicationInstances = client.getApplicationInstances(appName);
if (applicationInstances != null) {
return applicationInstances;
}
if (System.currentTimeMillis() - start > STARTUP_TIMEOUT) {
fail("Timed out waiting for startup");
break; // for the compiler
}
}
return null; // for the compiler
}
private void clearTestDomainAndRoutes() {
CloudDomain domain = getDomainNamed(TEST_DOMAIN, connectedClient.getDomains());
if (domain != null) {
List<CloudRoute> routes = connectedClient.getRoutes(domain.getName());
for (CloudRoute route : routes) {
connectedClient.deleteRoute(route.getHost(), route.getDomain().getName());
}
connectedClient.deleteDomain(domain.getName());
}
}
private CloudRoute getRouteWithHost(String hostName, List<CloudRoute> routes) {
for (CloudRoute route : routes) {
if (route.getHost().equals(hostName)) {
return route;
}
}
return null;
}
private CloudDomain getDomainNamed(String domainName, List<CloudDomain> domains) {
for (CloudDomain domain : domains) {
if (domain.getName().equals(domainName)) {
return domain;
}
}
return null;
}
private String computeAppUrl(String appName) {
return appName + "." + defaultDomainName;
}
private String computeAppUrlNoProtocol(String appName) {
return computeAppUrl(appName);
}
private void assertTimeWithinRange(String message, long actual, int timeTolerance) {
// Allow more time deviations due to local clock being out of sync with cloud
assertTrue(message,
Math.abs(System.currentTimeMillis() - actual) < timeTolerance);
}
private static abstract class NoOpUploadStatusCallback implements UploadStatusCallback {
public void onCheckResources() {
}
public void onMatchedFileNames(Set<String> matchedFileNames) {
}
public void onProcessMatchedResources(int length) {
}
}
private static class NonUnsubscribingUploadStatusCallback extends NoOpUploadStatusCallback {
public int progressCount = 0;
public boolean onProgress(String status) {
progressCount++;
return false;
}
}
private static class UnsubscribingUploadStatusCallback extends NoOpUploadStatusCallback {
public int progressCount = 0;
public boolean onProgress(String status) {
progressCount++;
// unsubscribe after the first report
return progressCount == 1;
}
}
private class AccumulatingApplicationLogListener implements ApplicationLogListener {
private List<ApplicationLog> logs = new ArrayList<ApplicationLog>();
public void onMessage(ApplicationLog log) {
logs.add(log);
}
public void onError(Throwable exception) {
fail(exception.getMessage());
}
public void onComplete() {
}
}
}