/*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.dash.test.mocks;
import static org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.v2.ReactorUtils.just;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.eclipse.core.runtime.Assert;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.CFAppState;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.CFApplication;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.CFApplicationDetail;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.CFInstanceState;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.CFInstanceStats;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.HealthChecks;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.InstanceState;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.v2.ApplicationExtras;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.v2.CFApplicationDetailData;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.v2.CFApplicationSummaryData;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.deployment.DeploymentProperties;
import org.springframework.ide.eclipse.boot.dash.util.CancelationTokens;
import org.springframework.ide.eclipse.boot.dash.util.CancelationTokens.CancelationToken;
import org.springsource.ide.eclipse.commons.frameworks.test.util.ACondition;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableMap;
import reactor.core.publisher.Mono;
public class MockCFApplication {
private static class MockCFInstanceStats implements CFInstanceStats {
private CFInstanceState state;
public MockCFInstanceStats(CFInstanceState state) {
this.state = state;
}
@Override
public CFInstanceState getState() {
return state;
}
@Override
public String toString() {
return "CFInstanceState("+state+")";
}
}
private final String name;
private final UUID guid;
private int instances;
private Map<String, String> env = new HashMap<>();
private int memory = 1024;
private List<String> services = new ArrayList<>();
private String buildpackUrl = null;
private List<String> uris = new ArrayList<>();
private CFAppState state = CFAppState.STOPPED;
private int diskQuota = 1024;
private Integer timeout = null;
private String healthCheckType = DeploymentProperties.DEFAULT_HEALTH_CHECK_TYPE;
private String command = null;
private String stack = null;
private MockCloudFoundryClientFactory owner;
private MockCFSpace space;
public MockCFApplication(MockCloudFoundryClientFactory owner, MockCFSpace space, String name, UUID guid, int instances, CFAppState state) {
this.owner = owner;
this.space = space;
this.name = name;
this.guid = guid;
this.instances = instances;
this.state = state;
this.cancelationTokens = new CancelationTokens();
}
private ImmutableList<CFInstanceStats> stats = ImmutableList.of();
private CancelationTokens cancelationTokens;
private byte[] bits;
public MockCFApplication(MockCloudFoundryClientFactory owner, MockCFSpace space, String name) {
this(owner,
space,
name,
UUID.randomUUID(),
1,
CFAppState.STOPPED
);
setUris(ImmutableList.of(name+"."+space.getDefaultDomain()));
}
public String getName() {
return name;
}
public List<CFInstanceStats> getStats() {
return stats;
}
public void start(CancelationToken cancelationToken) throws Exception {
Assert.isLegal(CFAppState.STOPPED==state);
Assert.isLegal(stats.isEmpty());
this.state = CFAppState.UNKNOWN;
final long endTime = System.currentTimeMillis()+getStartDelay();
new ACondition("simulated app starting (waiting)", getStartDelay()+1000) {
@Override
public boolean test() throws Exception {
// System.out.println("Checking token: "+cancelToken);
if (!cancelationToken.isCanceled() && System.currentTimeMillis()<endTime) {
// System.out.println("Starting "+getName()+"...");
throw new IOException("App still starting");
}
return true;
}
};
Builder<CFInstanceStats> builder = ImmutableList.builder();
for (int i = 0; i < instances; i++) {
Map<String, Object> values = new HashMap<>();
values.put("state", InstanceState.RUNNING.toString());
CFInstanceStats stat = new MockCFInstanceStats(CFInstanceState.RUNNING);
builder.add(stat);
}
if (cancelationToken.isCanceled()) {
System.out.println("Starting "+getName()+" CANCELED");
throw new IOException("Operation Canceled");
}
this.stats = builder.build();
this.state = CFAppState.STARTED;
System.out.println("Starting "+getName()+" SUCCESS");
}
private long getStartDelay() {
return owner.getStartDelay();
}
public String getHealthCheckType() {
return healthCheckType;
}
public void setHealthCheckType(String t) {
this.healthCheckType = t;
}
public void setHealthCheckTypeMaybe(String t) {
if (t!=null) {
setHealthCheckType(t);
}
}
// public int getInstances() {
// return instances;
// }
public int getRunningInstances() {
int runningInstances = 0;
for (CFInstanceStats instance : getStats()) {
if (instance.getState()==CFInstanceState.RUNNING) {
runningInstances++;
}
}
return runningInstances;
}
public UUID getGuid() {
return guid;
}
public void setBuildpackUrl(String buildpackUrl) {
this.buildpackUrl = buildpackUrl;
}
public void setCommand(String command) {
this.command = command;
}
public void setStack(String stack) {
this.stack = stack;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public void setDiskQuota(int diskQuota) {
this.diskQuota = diskQuota;
}
public void setMemory(int memory) {
this.memory = memory;
}
public int getMemory() {
return this.memory;
}
public void setUris(Collection<String> uris) {
this.uris = uris==null?null:ImmutableList.copyOf(uris);
}
public void setServices(Collection<String> services) {
this.services = services==null?null:ImmutableList.copyOf(services);
}
public CFApplication getBasicInfo() {
return new CFApplicationSummaryData(
name,
instances,
getRunningInstances(),
memory,
guid,
uris,
state,
diskQuota,
getExtras()
);
}
private ApplicationExtras getExtras() {
return new ApplicationExtras() {
@Override
public Mono<String> getStack() {
return just(stack);
}
@Override
public Mono<List<String>> getServices() {
return just(services);
}
@Override
public Mono<Map<String, String>> getEnv() {
return just(env);
}
@Override
public Mono<String> getBuildpack() {
return just(buildpackUrl);
}
@Override
public Mono<Integer> getTimeout() {
return just(timeout);
}
@Override
public Mono<String> getCommand() {
return just(command);
}
@Override
public Mono<String> getHealthCheckType() {
return just(healthCheckType);
}
};
}
public CFApplicationDetail getDetailedInfo() {
return new CFApplicationDetailData(
new CFApplicationSummaryData(
name,
instances,
getRunningInstances(),
memory,
guid,
uris,
state,
diskQuota,
getExtras()
),
ImmutableList.copyOf(stats)
);
// return new CFApplicationDetailData(getBasicInfo(), ImmutableList.copyOf(stats));
}
@Override
public String toString() {
return "MockCFApp("+name+")";
}
public void stop() {
cancelationTokens.cancelAll();
this.stats = ImmutableList.of();
this.state = CFAppState.STOPPED;
}
public Map<String, String> getEnv() {
return env;
}
public void setEnv(Map<String, String> newEnv) {
env = ImmutableMap.copyOf(newEnv);
}
public void restart(CancelationToken cancelationToken) throws Exception {
stop();
start(cancelationToken);
}
public void scaleInstances(int desiredInstances) {
Assert.isLegal(desiredInstances>0);
Builder<CFInstanceStats> builder = ImmutableList.builder();
builder.addAll(stats);
for (int i = 0; i < desiredInstances; i++) {
builder.add(new MockCFInstanceStats(CFInstanceState.RUNNING));
}
stats = builder.build();
this.instances = desiredInstances;
}
public void setBuildpackUrlMaybe(String buildpack) {
if (buildpack!=null) {
setBuildpackUrl(buildpack);
}
}
public void setCommandMaybe(String command) {
if (command!=null) {
setCommand(command);
}
}
public void setDiskQuotaMaybe(Integer diskQuota) {
if (diskQuota!=null) {
setDiskQuota(diskQuota);
}
}
public void setEnvMaybe(Map<String, String> env) {
if (env!=null) {
setEnv(env);
}
}
public void setMemoryMaybe(Integer memory) {
if (memory!=null) {
setMemory(memory);
}
}
public void setServicesMaybe(List<String> services) {
if (services!=null) {
setServices(services);
}
}
public void setStackMaybe(String stack) {
if (stack!=null) {
setStack(stack);
}
}
public void setTimeoutMaybe(Integer timeout) {
if (timeout!=null) {
setTimeout(timeout);
}
}
public int getPushCount() {
return space.getPushCount(name).getValue();
}
public String getFileContents(String path) throws IOException {
ZipInputStream zip = new ZipInputStream(new ByteArrayInputStream(this.bits));
ZipEntry entry;
while (null != (entry = zip.getNextEntry())) {
if (!entry.isDirectory()) {
if (entry.getName().equals(path)) {
return new String(readBytes(zip));
}
}
}
return null;
}
private byte[] readBytes(ZipInputStream zip) throws IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
int nextByte;
while ((nextByte = zip.read())>=0) {
bytes.write(nextByte);
}
return bytes.toByteArray();
}
public void setBits(byte[] bytes) {
this.bits = bytes;
}
public InputStream getBits() {
return new ByteArrayInputStream(bits);
}
}