/*
* Copyright © 2014-2015 Cask Data, Inc.
*
* Licensed 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 co.cask.cdap.internal.app.services.http;
import co.cask.cdap.api.Config;
import co.cask.cdap.api.metrics.MetricsCollectionService;
import co.cask.cdap.api.schedule.ScheduleSpecification;
import co.cask.cdap.app.program.ManifestFields;
import co.cask.cdap.app.store.ServiceStore;
import co.cask.cdap.client.DatasetClient;
import co.cask.cdap.client.StreamClient;
import co.cask.cdap.client.StreamViewClient;
import co.cask.cdap.client.config.ClientConfig;
import co.cask.cdap.client.config.ConnectionConfig;
import co.cask.cdap.common.conf.CConfiguration;
import co.cask.cdap.common.conf.Constants;
import co.cask.cdap.common.discovery.EndpointStrategy;
import co.cask.cdap.common.discovery.RandomEndpointStrategy;
import co.cask.cdap.common.io.Locations;
import co.cask.cdap.common.lang.jar.BundleJarUtil;
import co.cask.cdap.common.utils.Tasks;
import co.cask.cdap.data.stream.service.StreamService;
import co.cask.cdap.data2.datafabric.dataset.service.DatasetService;
import co.cask.cdap.data2.datafabric.dataset.service.executor.DatasetOpExecutor;
import co.cask.cdap.internal.app.services.AppFabricServer;
import co.cask.cdap.internal.guice.AppFabricTestModule;
import co.cask.cdap.internal.test.AppJarHelper;
import co.cask.cdap.internal.test.PluginJarHelper;
import co.cask.cdap.metadata.MetadataService;
import co.cask.cdap.metrics.query.MetricsQueryService;
import co.cask.cdap.proto.Id;
import co.cask.cdap.proto.NamespaceMeta;
import co.cask.cdap.proto.RunRecord;
import co.cask.cdap.proto.StreamProperties;
import co.cask.cdap.proto.ViewSpecification;
import co.cask.cdap.proto.artifact.AppRequest;
import co.cask.cdap.proto.artifact.ArtifactRange;
import co.cask.tephra.TransactionManager;
import co.cask.tephra.TransactionSystemClient;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ObjectArrays;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.FileEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.apache.twill.discovery.Discoverable;
import org.apache.twill.discovery.DiscoveryServiceClient;
import org.apache.twill.discovery.ServiceDiscovered;
import org.apache.twill.filesystem.Location;
import org.apache.twill.filesystem.LocationFactory;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.rules.TemporaryFolder;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.jar.Manifest;
import javax.annotation.Nullable;
import javax.ws.rs.core.MediaType;
/**
* AppFabric HttpHandler Test classes can extend this class, this will allow the HttpService be setup before
* running the handler tests, this also gives the ability to run individual test cases.
*/
public abstract class AppFabricTestBase {
protected static final Gson GSON = new Gson();
private static final String API_KEY = "SampleTestApiKey";
private static final Header AUTH_HEADER = new BasicHeader(Constants.Gateway.API_KEY, API_KEY);
protected static final Type MAP_STRING_STRING_TYPE = new TypeToken<Map<String, String>>() { }.getType();
protected static final Type LIST_MAP_STRING_STRING_TYPE = new TypeToken<List<Map<String, String>>>() { }.getType();
protected static final Type LIST_RUNRECORD_TYPE = new TypeToken<List<RunRecord>>() { }.getType();
protected static final String NONEXISTENT_NAMESPACE = "12jr0j90jf3foieoi33";
protected static final String TEST_NAMESPACE1 = "testnamespace1";
protected static final NamespaceMeta TEST_NAMESPACE_META1 = new NamespaceMeta.Builder()
.setName(TEST_NAMESPACE1)
.setDescription(TEST_NAMESPACE1)
.build();
protected static final String TEST_NAMESPACE2 = "testnamespace2";
protected static final NamespaceMeta TEST_NAMESPACE_META2 = new NamespaceMeta.Builder()
.setName(TEST_NAMESPACE2)
.setDescription(TEST_NAMESPACE2)
.build();
private static final String hostname = "127.0.0.1";
private static int port;
private static Injector injector;
private static TransactionManager txManager;
private static AppFabricServer appFabricServer;
private static MetricsQueryService metricsService;
private static MetricsCollectionService metricsCollectionService;
private static DatasetOpExecutor dsOpService;
private static DatasetService datasetService;
private static TransactionSystemClient txClient;
private static StreamService streamService;
private static ServiceStore serviceStore;
private static MetadataService metadataService;
private static LocationFactory locationFactory;
private static StreamClient streamClient;
private static StreamViewClient streamViewClient;
private static DatasetClient datasetClient;
@ClassRule
public static TemporaryFolder tmpFolder = new TemporaryFolder();
@BeforeClass
public static void beforeClass() throws Throwable {
CConfiguration conf = CConfiguration.create();
conf.set(Constants.AppFabric.SERVER_ADDRESS, hostname);
conf.set(Constants.CFG_LOCAL_DATA_DIR, tmpFolder.newFolder("data").getAbsolutePath());
conf.set(Constants.AppFabric.OUTPUT_DIR, System.getProperty("java.io.tmpdir"));
conf.set(Constants.AppFabric.TEMP_DIR, System.getProperty("java.io.tmpdir"));
conf.setBoolean(Constants.Dangerous.UNRECOVERABLE_RESET, true);
injector = Guice.createInjector(new AppFabricTestModule(conf));
txManager = injector.getInstance(TransactionManager.class);
txManager.startAndWait();
dsOpService = injector.getInstance(DatasetOpExecutor.class);
dsOpService.startAndWait();
datasetService = injector.getInstance(DatasetService.class);
datasetService.startAndWait();
appFabricServer = injector.getInstance(AppFabricServer.class);
appFabricServer.startAndWait();
DiscoveryServiceClient discoveryClient = injector.getInstance(DiscoveryServiceClient.class);
ServiceDiscovered appFabricHttpDiscovered = discoveryClient.discover(Constants.Service.APP_FABRIC_HTTP);
EndpointStrategy endpointStrategy = new RandomEndpointStrategy(appFabricHttpDiscovered);
port = endpointStrategy.pick(1, TimeUnit.SECONDS).getSocketAddress().getPort();
txClient = injector.getInstance(TransactionSystemClient.class);
metricsCollectionService = injector.getInstance(MetricsCollectionService.class);
metricsCollectionService.startAndWait();
metricsService = injector.getInstance(MetricsQueryService.class);
metricsService.startAndWait();
streamService = injector.getInstance(StreamService.class);
streamService.startAndWait();
serviceStore = injector.getInstance(ServiceStore.class);
serviceStore.startAndWait();
metadataService = injector.getInstance(MetadataService.class);
metadataService.startAndWait();
locationFactory = getInjector().getInstance(LocationFactory.class);
streamClient = new StreamClient(getClientConfig(discoveryClient, Constants.Service.STREAMS));
streamViewClient = new StreamViewClient(getClientConfig(discoveryClient, Constants.Service.STREAMS));
datasetClient = new DatasetClient(getClientConfig(discoveryClient, Constants.Service.DATASET_MANAGER));
createNamespaces();
}
@AfterClass
public static void afterClass() throws Exception {
deleteNamespaces();
streamService.stopAndWait();
appFabricServer.stopAndWait();
metricsCollectionService.stopAndWait();
metricsService.stopAndWait();
datasetService.stopAndWait();
dsOpService.stopAndWait();
txManager.stopAndWait();
serviceStore.stopAndWait();
metadataService.stopAndWait();
}
protected static Injector getInjector() {
return injector;
}
protected static TransactionSystemClient getTxClient() {
return txClient;
}
protected static int getPort() {
return port;
}
protected static URI getEndPoint(String path) throws URISyntaxException {
return new URI("http://" + hostname + ":" + port + path);
}
protected static HttpResponse doGet(String resource) throws Exception {
return doGet(resource, null);
}
protected static HttpResponse doGet(String resource, Header[] headers) throws Exception {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(getEndPoint(resource));
if (headers != null) {
get.setHeaders(ObjectArrays.concat(AUTH_HEADER, headers));
} else {
get.setHeader(AUTH_HEADER);
}
return client.execute(get);
}
protected static HttpResponse execute(HttpUriRequest request) throws Exception {
DefaultHttpClient client = new DefaultHttpClient();
request.setHeader(AUTH_HEADER);
return client.execute(request);
}
protected static HttpPost getPost(String resource) throws Exception {
HttpPost post = new HttpPost(getEndPoint(resource));
post.setHeader(AUTH_HEADER);
return post;
}
protected static HttpPut getPut(String resource) throws Exception {
HttpPut put = new HttpPut(getEndPoint(resource));
put.setHeader(AUTH_HEADER);
return put;
}
protected static HttpResponse doPost(String resource) throws Exception {
return doPost(resource, null, null);
}
protected static HttpResponse doPost(String resource, String body) throws Exception {
return doPost(resource, body, null);
}
protected static HttpResponse doPost(String resource, String body, Header[] headers) throws Exception {
DefaultHttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(getEndPoint(resource));
if (body != null) {
post.setEntity(new StringEntity(body));
}
if (headers != null) {
post.setHeaders(ObjectArrays.concat(AUTH_HEADER, headers));
} else {
post.setHeader(AUTH_HEADER);
}
return client.execute(post);
}
protected static HttpResponse doPost(HttpPost post) throws Exception {
DefaultHttpClient client = new DefaultHttpClient();
post.setHeader(AUTH_HEADER);
return client.execute(post);
}
protected static HttpResponse doPut(String resource) throws Exception {
HttpPut put = new HttpPut(getEndPoint(resource));
put.setHeader(AUTH_HEADER);
return doPut(resource, null);
}
protected static HttpResponse doPut(String resource, String body) throws Exception {
DefaultHttpClient client = new DefaultHttpClient();
HttpPut put = new HttpPut(getEndPoint(resource));
if (body != null) {
put.setEntity(new StringEntity(body));
}
put.setHeader(AUTH_HEADER);
return client.execute(put);
}
protected static HttpResponse doDelete(String resource) throws Exception {
DefaultHttpClient client = new DefaultHttpClient();
HttpDelete delete = new HttpDelete(getEndPoint(resource));
delete.setHeader(AUTH_HEADER);
return client.execute(delete);
}
protected static String readResponse(HttpResponse response) throws IOException {
HttpEntity entity = response.getEntity();
return EntityUtils.toString(entity, "UTF-8");
}
protected static <T> T readResponse(HttpResponse response, Type type) throws IOException {
return GSON.fromJson(readResponse(response), type);
}
protected static <T> T readResponse(HttpResponse response, Type type, Gson gson) throws IOException {
return gson.fromJson(readResponse(response), type);
}
protected HttpResponse addAppArtifact(Id.Artifact artifactId, Class<?> cls) throws Exception {
Location appJar = AppJarHelper.createDeploymentJar(locationFactory, cls, new Manifest());
try (InputStream artifactInputStream = appJar.getInputStream()) {
return addArtifact(artifactId, artifactInputStream, null);
} finally {
appJar.delete();
}
}
protected HttpResponse addPluginArtifact(Id.Artifact artifactId, Class<?> cls,
Manifest manifest,
Set<ArtifactRange> parents) throws Exception {
Location appJar = PluginJarHelper.createPluginJar(locationFactory, manifest, cls);
try (InputStream artifactInputStream = appJar.getInputStream()) {
return addArtifact(artifactId, artifactInputStream, parents);
} finally {
appJar.delete();
}
}
// add an artifact and return the response code
protected HttpResponse addArtifact(Id.Artifact artifactId, InputStream artifactContents,
Set<ArtifactRange> parents) throws Exception {
String path = getVersionedAPIPath("artifacts/" + artifactId.getName(), artifactId.getNamespace().getId());
HttpEntityEnclosingRequestBase request = getPost(path);
request.setHeader(Constants.Gateway.API_KEY, "api-key-example");
request.setHeader("Artifact-Version", artifactId.getVersion().getVersion());
if (parents != null && !parents.isEmpty()) {
request.setHeader("Artifact-Extends", Joiner.on('/').join(parents));
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteStreams.copy(artifactContents, bos);
bos.close();
request.setEntity(new ByteArrayEntity(bos.toByteArray()));
return execute(request);
}
// add artifact properties and return the response code
protected HttpResponse addArtifactProperties(Id.Artifact artifactId,
Map<String, String> properties) throws Exception {
String nonNamespacePath = String.format("artifacts/%s/versions/%s/properties",
artifactId.getName(), artifactId.getVersion());
String path = getVersionedAPIPath(nonNamespacePath, artifactId.getNamespace().getId());
HttpEntityEnclosingRequestBase request = getPut(path);
request.setEntity(new ByteArrayEntity(properties.toString().getBytes()));
return execute(request);
}
/**
* Deploys an application.
*/
protected HttpResponse deploy(Class<?> application) throws Exception {
return deploy(application, null, null);
}
protected HttpResponse deploy(Class<?> application, @Nullable String apiVersion, @Nullable String namespace)
throws Exception {
return deploy(application, apiVersion, namespace, null, null);
}
protected HttpResponse deploy(Id.Application appId,
AppRequest<? extends Config> appRequest) throws Exception {
HttpEntityEnclosingRequestBase request;
String deployPath = getVersionedAPIPath("apps/" + appId.getId(), appId.getNamespaceId());
request = getPut(deployPath);
request.setHeader(Constants.Gateway.API_KEY, "api-key-example");
request.setHeader(HttpHeaders.Names.CONTENT_TYPE, MediaType.APPLICATION_JSON);
request.setEntity(new StringEntity(GSON.toJson(appRequest)));
return execute(request);
}
/**
* Deploys an application with (optionally) a defined app name and app version
*/
protected HttpResponse deploy(Class<?> application, @Nullable String apiVersion, @Nullable String namespace,
@Nullable String appVersion, @Nullable Config appConfig) throws Exception {
namespace = namespace == null ? Id.Namespace.DEFAULT.getId() : namespace;
apiVersion = apiVersion == null ? Constants.Gateway.API_VERSION_3_TOKEN : apiVersion;
appVersion = appVersion == null ? String.format("1.0.%d", System.currentTimeMillis()) : appVersion;
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(ManifestFields.BUNDLE_VERSION, appVersion);
File artifactJar = buildAppArtifact(application, application.getSimpleName(), manifest);
File expandDir = tmpFolder.newFolder();
BundleJarUtil.unJar(Locations.toLocation(artifactJar), expandDir);
// Add webapp
File webAppFile = new File(expandDir, "webapp/default/netlens/src/1.txt");
webAppFile.getParentFile().mkdirs();
Files.write("dummy data", webAppFile, Charsets.UTF_8);
BundleJarUtil.createJar(expandDir, artifactJar);
HttpEntityEnclosingRequestBase request;
String versionedApiPath = getVersionedAPIPath("apps/", apiVersion, namespace);
request = getPost(versionedApiPath);
request.setHeader(Constants.Gateway.API_KEY, "api-key-example");
request.setHeader("X-Archive-Name", String.format("%s-%s.jar", application.getSimpleName(), appVersion));
if (appConfig != null) {
request.setHeader("X-App-Config", GSON.toJson(appConfig));
}
request.setEntity(new FileEntity(artifactJar));
return execute(request);
}
protected String getVersionedAPIPath(String nonVersionedApiPath, String namespace) {
return getVersionedAPIPath(nonVersionedApiPath, Constants.Gateway.API_VERSION_3_TOKEN, namespace);
}
protected String getVersionedAPIPath(String nonVersionedApiPath, String version, String namespace) {
if (!Constants.Gateway.API_VERSION_3_TOKEN.equals(version)) {
throw new IllegalArgumentException(
String.format("Unsupported version '%s'. Only v3 is supported.", version));
}
Preconditions.checkArgument(namespace != null, "Namespace cannot be null for v3 APIs.");
return String.format("/%s/namespaces/%s/%s", version, namespace, nonVersionedApiPath);
}
protected List<JsonObject> getAppList(String namespace) throws Exception {
HttpResponse response = doGet(getVersionedAPIPath("apps/", Constants.Gateway.API_VERSION_3_TOKEN, namespace));
Assert.assertEquals(200, response.getStatusLine().getStatusCode());
Type typeToken = new TypeToken<List<JsonObject>>() { }.getType();
return readResponse(response, typeToken);
}
protected JsonObject getAppDetails(String namespace, String appName) throws Exception {
HttpResponse response = doGet(getVersionedAPIPath(String.format("apps/%s", appName),
Constants.Gateway.API_VERSION_3_TOKEN, namespace));
Assert.assertEquals(200, response.getStatusLine().getStatusCode());
Assert.assertEquals("application/json", response.getFirstHeader(HttpHeaders.Names.CONTENT_TYPE).getValue());
Type typeToken = new TypeToken<JsonObject>() { }.getType();
return readResponse(response, typeToken);
}
protected void assertRunHistory(final Id.Program program, final String status, int expected,
long timeout, TimeUnit timeoutUnit) throws Exception {
Tasks.waitFor(expected, new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return getProgramRuns(program, status).size();
}
}, timeout, timeoutUnit, 100, TimeUnit.MILLISECONDS);
}
/**
* Checks the given schedule states.
*/
protected void assertSchedule(final Id.Program program, final String scheduleName,
boolean scheduled, long timeout, TimeUnit timeoutUnit) throws Exception {
Tasks.waitFor(scheduled, new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
String statusURL = getVersionedAPIPath(String.format("apps/%s/schedules/%s/status",
program.getApplicationId(), scheduleName),
Constants.Gateway.API_VERSION_3_TOKEN, program.getNamespaceId());
HttpResponse response = doGet(statusURL);
Preconditions.checkState(200 == response.getStatusLine().getStatusCode());
Map<String, String> result = GSON.fromJson(EntityUtils.toString(response.getEntity()),
MAP_STRING_STRING_TYPE);
return result != null && "SCHEDULED".equals(result.get("status"));
}
}, timeout, timeoutUnit, 100, TimeUnit.MILLISECONDS);
}
protected void deleteApp(Id.Application app, int expectedResponseCode) throws Exception {
HttpResponse response = doDelete(getVersionedAPIPath("apps/" + app.getId(), app.getNamespaceId()));
Assert.assertEquals(expectedResponseCode, response.getStatusLine().getStatusCode());
}
protected void deleteApp(final Id.Application app, int expectedResponseCode,
long timeout, TimeUnit timeoutUnit) throws Exception {
Tasks.waitFor(expectedResponseCode, new Callable<Integer>() {
@Override
public Integer call() throws Exception {
HttpResponse response = doDelete(getVersionedAPIPath("apps/" + app.getId(), app.getNamespaceId()));
return response.getStatusLine().getStatusCode();
}
}, timeout, timeoutUnit, 100, TimeUnit.MILLISECONDS);
}
protected List<JsonObject> getArtifacts(String namespace) throws Exception {
HttpResponse response = doGet(getVersionedAPIPath("artifacts", namespace));
Assert.assertEquals(200, response.getStatusLine().getStatusCode());
Type typeToken = new TypeToken<List<JsonObject>>() { }.getType();
return readResponse(response, typeToken);
}
protected void deleteArtifact(Id.Artifact artifact, int expectedResponseCode) throws Exception {
String path = String.format("artifacts/%s/versions/%s", artifact.getName(), artifact.getVersion().getVersion());
HttpResponse response = doDelete(getVersionedAPIPath(path, artifact.getNamespace().getId()));
Assert.assertEquals(expectedResponseCode, response.getStatusLine().getStatusCode());
}
/**
* Starts the given program.
*/
protected void startProgram(Id.Program program) throws Exception {
startProgram(program, 200);
}
/**
* Tries to start the given program and expect the call completed with the status.
*/
protected void startProgram(Id.Program program, int expectedStatusCode) throws Exception {
startProgram(program, ImmutableMap.<String, String>of(), expectedStatusCode);
}
/**
* Starts the given program with the given runtime arguments.
*/
protected void startProgram(Id.Program program, Map<String, String> args) throws Exception {
startProgram(program, args, 200);
}
/**
* Tries to start the given program with the given runtime arguments and expect the call completed with the status.
*/
protected void startProgram(Id.Program program, Map<String, String> args, int expectedStatusCode) throws Exception {
String path = String.format("apps/%s/%s/%s/start",
program.getApplicationId(),
program.getType().getCategoryName(),
program.getId());
HttpResponse response = doPost(getVersionedAPIPath(path, program.getNamespaceId()), GSON.toJson(args));
Assert.assertEquals(expectedStatusCode, response.getStatusLine().getStatusCode());
}
/**
* Tries to start the given program with the given runtime arguments and expect the call completed with the status.
*/
protected void debugProgram(Id.Program program, int expectedStatusCode) throws Exception {
String path = String.format("apps/%s/%s/%s/debug",
program.getApplicationId(),
program.getType().getCategoryName(),
program.getId());
HttpResponse response = doPost(getVersionedAPIPath(path, program.getNamespaceId()),
GSON.toJson(ImmutableMap.<String, String>of()));
Assert.assertEquals(expectedStatusCode, response.getStatusLine().getStatusCode());
}
/**
* Stops the given program.
*/
protected void stopProgram(Id.Program program) throws Exception {
stopProgram(program, 200);
}
/**
* Tries to stop the given program and expect the call completed with the status.
*/
protected void stopProgram(Id.Program program, int expectedStatusCode) throws Exception {
stopProgram(program, null, expectedStatusCode);
}
protected void stopProgram(Id.Program program, String runId, int expectedStatusCode) throws Exception {
stopProgram(program, runId, expectedStatusCode, null);
}
protected void stopProgram(Id.Program program, String runId, int expectedStatusCode, String expectedMessage)
throws Exception {
String path;
if (runId == null) {
path = String.format("apps/%s/%s/%s/stop", program.getApplicationId(), program.getType().getCategoryName(),
program.getId());
} else {
path = String.format("apps/%s/%s/%s/runs/%s/stop", program.getApplicationId(),
program.getType().getCategoryName(), program.getId(), runId);
}
HttpResponse response = doPost(getVersionedAPIPath(path, program.getNamespaceId()));
Assert.assertEquals(expectedStatusCode, response.getStatusLine().getStatusCode());
if (expectedMessage != null) {
Assert.assertEquals(expectedMessage, EntityUtils.toString(response.getEntity()));
}
}
/**
* Waits for the given program to transit to the given state.
*/
protected void waitState(final Id.Program programId, String state) throws Exception {
Tasks.waitFor(state, new Callable<String>() {
@Override
public String call() throws Exception {
String path = String.format("apps/%s/%s/%s/status",
programId.getApplicationId(),
programId.getType().getCategoryName(), programId.getId());
HttpResponse response = doGet(getVersionedAPIPath(path, programId.getNamespaceId()));
JsonObject status = GSON.fromJson(EntityUtils.toString(response.getEntity()), JsonObject.class);
if (status == null || !status.has("status")) {
return null;
}
return status.get("status").getAsString();
}
}, 60, TimeUnit.SECONDS);
}
private static void createNamespaces() throws Exception {
HttpResponse response = doPut(String.format("%s/namespaces/%s", Constants.Gateway.API_VERSION_3, TEST_NAMESPACE1),
GSON.toJson(TEST_NAMESPACE_META1));
Assert.assertEquals(200, response.getStatusLine().getStatusCode());
response = doPut(String.format("%s/namespaces/%s", Constants.Gateway.API_VERSION_3, TEST_NAMESPACE2),
GSON.toJson(TEST_NAMESPACE_META2));
Assert.assertEquals(200, response.getStatusLine().getStatusCode());
}
private static void deleteNamespaces() throws Exception {
HttpResponse response = doDelete(String.format("%s/unrecoverable/namespaces/%s", Constants.Gateway.API_VERSION_3,
TEST_NAMESPACE1));
Assert.assertEquals(200, response.getStatusLine().getStatusCode());
response = doDelete(String.format("%s/unrecoverable/namespaces/%s", Constants.Gateway.API_VERSION_3,
TEST_NAMESPACE2));
Assert.assertEquals(200, response.getStatusLine().getStatusCode());
}
protected String getProgramStatus(Id.Program program) throws Exception {
return getStatus(programStatus(program));
}
protected void programStatus(Id.Program program, int expectedStatus) throws Exception {
Assert.assertEquals(expectedStatus, programStatus(program).getStatusLine().getStatusCode());
}
protected HttpResponse programStatus(Id.Program program) throws Exception {
String path = String.format("apps/%s/%s/%s/status",
program.getApplicationId(),
program.getType().getCategoryName(),
program.getId());
return doGet(getVersionedAPIPath(path, program.getNamespaceId()));
}
private String getStatus(HttpResponse response) throws Exception {
Assert.assertEquals(200, response.getStatusLine().getStatusCode());
String s = EntityUtils.toString(response.getEntity());
Map<String, String> o = GSON.fromJson(s, MAP_STRING_STRING_TYPE);
return o.get("status");
}
protected int suspendSchedule(String namespace, String appName, String schedule) throws Exception {
String scheduleSuspend = String.format("apps/%s/schedules/%s/suspend", appName, schedule);
String versionedScheduledSuspend = getVersionedAPIPath(scheduleSuspend, Constants.Gateway.API_VERSION_3_TOKEN,
namespace);
HttpResponse response = doPost(versionedScheduledSuspend);
return response.getStatusLine().getStatusCode();
}
protected int resumeSchedule(String namespace, String appName, String schedule) throws Exception {
String scheduleResume = String.format("apps/%s/schedules/%s/resume", appName, schedule);
HttpResponse response = doPost(getVersionedAPIPath(scheduleResume, Constants.Gateway.API_VERSION_3_TOKEN,
namespace));
return response.getStatusLine().getStatusCode();
}
protected List<ScheduleSpecification> getSchedules(String namespace, String appName, String workflowName)
throws Exception {
String schedulesUrl = String.format("apps/%s/workflows/%s/schedules", appName, workflowName);
String versionedUrl = getVersionedAPIPath(schedulesUrl, Constants.Gateway.API_VERSION_3_TOKEN, namespace);
HttpResponse response = doGet(versionedUrl);
String json = EntityUtils.toString(response.getEntity());
return GSON.fromJson(json, new TypeToken<List<ScheduleSpecification>>() { }.getType());
}
protected void verifyNoRunWithStatus(final Id.Program program, final String status) throws Exception {
Tasks.waitFor(0, new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return getProgramRuns(program, status).size();
}
}, 60, TimeUnit.SECONDS);
}
protected void verifyProgramRuns(Id.Program program, String status) throws Exception {
verifyProgramRuns(program, status, 0);
}
protected void verifyProgramRuns(final Id.Program program, final String status, final int expected)
throws Exception {
Tasks.waitFor(true, new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return getProgramRuns(program, status).size() > expected;
}
}, 60, TimeUnit.SECONDS);
}
protected List<RunRecord> getProgramRuns(Id.Program program, String status) throws Exception {
String path = String.format("apps/%s/%s/%s/runs?status=%s", program.getApplicationId(),
program.getType().getCategoryName(), program.getId(), status);
HttpResponse response = doGet(getVersionedAPIPath(path, program.getNamespaceId()));
Assert.assertEquals(200, response.getStatusLine().getStatusCode());
String json = EntityUtils.toString(response.getEntity());
return GSON.fromJson(json, LIST_RUNRECORD_TYPE);
}
protected boolean createOrUpdateView(Id.Stream.View viewId, ViewSpecification spec) throws Exception {
return streamViewClient.createOrUpdate(viewId, spec);
}
protected void deleteStream(Id.Stream stream) throws Exception {
streamClient.delete(stream);
}
protected void deleteView(Id.Stream.View view) throws Exception {
streamViewClient.delete(view);
}
protected void setStreamProperties(Id.Stream stream, StreamProperties props) throws Exception {
streamClient.setStreamProperties(stream, props);
}
protected void updateDatasetProperties(Id.DatasetInstance dataset, Map<String, String> properties) throws Exception {
datasetClient.updateExisting(dataset, properties);
}
protected void deleteDataset(Id.DatasetInstance datasetInstance) throws Exception {
datasetClient.delete(datasetInstance);
}
protected HttpResponse createNamespace(String id) throws Exception {
return doPut(String.format("%s/namespaces/%s", Constants.Gateway.API_VERSION_3, id));
}
protected HttpResponse deleteNamespace(String name) throws Exception {
return doDelete(String.format("%s/unrecoverable/namespaces/%s", Constants.Gateway.API_VERSION_3, name));
}
protected HttpResponse createNamespace(String metadata, String id) throws Exception {
return doPut(String.format("%s/namespaces/%s", Constants.Gateway.API_VERSION_3, id), metadata);
}
protected HttpResponse listAllNamespaces() throws Exception {
return doGet(String.format("%s/namespaces", Constants.Gateway.API_VERSION_3));
}
protected HttpResponse getNamespace(String name) throws Exception {
Preconditions.checkArgument(name != null, "namespace name cannot be null");
return doGet(String.format("%s/namespaces/%s", Constants.Gateway.API_VERSION_3, name));
}
protected HttpResponse deleteNamespaceData(String name) throws Exception {
return doDelete(String.format("%s/unrecoverable/namespaces/%s/datasets", Constants.Gateway.API_VERSION_3, name));
}
protected HttpResponse setProperties(String id, NamespaceMeta meta) throws Exception {
return doPut(String.format("%s/namespaces/%s/properties", Constants.Gateway.API_VERSION_3, id),
GSON.toJson(meta));
}
protected File buildAppArtifact(Class<?> cls, String name) throws IOException {
return buildAppArtifact(cls, name, new Manifest());
}
protected File buildAppArtifact(Class<?> cls, String name, Manifest manifest) throws IOException {
if (!name.endsWith(".jar")) {
name += ".jar";
}
Location appJar = AppJarHelper.createDeploymentJar(locationFactory, cls, manifest);
File destination = new File(tmpFolder.newFolder(), name);
Files.copy(Locations.newInputSupplier(appJar), destination);
return destination;
}
private static ClientConfig getClientConfig(DiscoveryServiceClient discoveryClient, String service) {
EndpointStrategy endpointStrategy =
new RandomEndpointStrategy(discoveryClient.discover(service));
Discoverable discoverable = endpointStrategy.pick(1, TimeUnit.SECONDS);
Assert.assertNotNull(discoverable);
int port = discoverable.getSocketAddress().getPort();
ConnectionConfig connectionConfig = ConnectionConfig.builder().setHostname(hostname).setPort(port).build();
return ClientConfig.builder().setConnectionConfig(connectionConfig).build();
}
}