/*
* 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.gateway;
import co.cask.cdap.api.metrics.MetricsCollectionService;
import co.cask.cdap.common.conf.CConfiguration;
import co.cask.cdap.common.conf.Constants;
import co.cask.cdap.common.namespace.NamespaceAdmin;
import co.cask.cdap.common.namespace.guice.NamespaceClientRuntimeModule;
import co.cask.cdap.common.utils.Networks;
import co.cask.cdap.data.runtime.LocationStreamFileWriterFactory;
import co.cask.cdap.data.stream.StreamFileWriterFactory;
import co.cask.cdap.data.stream.service.StreamService;
import co.cask.cdap.data.stream.service.StreamServiceRuntimeModule;
import co.cask.cdap.data2.datafabric.dataset.service.DatasetService;
import co.cask.cdap.data2.datafabric.dataset.service.executor.DatasetOpExecutor;
import co.cask.cdap.data2.transaction.stream.FileStreamAdmin;
import co.cask.cdap.data2.transaction.stream.StreamAdmin;
import co.cask.cdap.data2.transaction.stream.StreamConsumerFactory;
import co.cask.cdap.data2.transaction.stream.StreamConsumerStateStoreFactory;
import co.cask.cdap.data2.transaction.stream.leveldb.LevelDBStreamConsumerStateStoreFactory;
import co.cask.cdap.data2.transaction.stream.leveldb.LevelDBStreamFileConsumerFactory;
import co.cask.cdap.gateway.handlers.log.MockLogReader;
import co.cask.cdap.gateway.router.NettyRouter;
import co.cask.cdap.internal.app.services.AppFabricServer;
import co.cask.cdap.internal.guice.AppFabricTestModule;
import co.cask.cdap.logging.read.LogReader;
import co.cask.cdap.metrics.query.MetricsQueryService;
import co.cask.cdap.notifications.guice.NotificationServiceRuntimeModule;
import co.cask.cdap.notifications.service.NotificationService;
import co.cask.cdap.proto.Id;
import co.cask.cdap.proto.NamespaceMeta;
import co.cask.cdap.security.guice.InMemorySecurityModule;
import co.cask.tephra.TransactionManager;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.google.inject.util.Modules;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.rules.TemporaryFolder;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
*
*/
// TODO: refactor this test. It is complete mess
public abstract class GatewayTestBase {
private 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);
private static final String hostname = "127.0.0.1";
private static int port;
@ClassRule
public static final TemporaryFolder TEMP_FOLDER = new TemporaryFolder();
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 CConfiguration conf;
private static Injector injector;
private static AppFabricServer appFabricServer;
private static NettyRouter router;
private static MetricsQueryService metricsQueryService;
private static MetricsCollectionService metricsCollectionService;
private static TransactionManager txService;
private static DatasetOpExecutor dsOpService;
private static DatasetService datasetService;
private static NotificationService notificationService;
private static StreamService streamService;
protected static NamespaceAdmin namespaceAdmin;
private static TemporaryFolder tmpFolder = new TemporaryFolder();
// Controls for test suite for whether to run BeforeClass/AfterClass
public static boolean runBefore = true;
public static boolean runAfter = true;
@BeforeClass
public static void beforeClass() throws Exception {
if (!runBefore) {
return;
}
tmpFolder.create();
conf = CConfiguration.create();
conf.setBoolean(Constants.Dangerous.UNRECOVERABLE_RESET, true);
conf.set(Constants.Router.ADDRESS, hostname);
conf.setInt(Constants.Router.ROUTER_PORT, 0);
conf.set(Constants.CFG_LOCAL_DATA_DIR, tmpFolder.newFolder().getAbsolutePath());
injector = startGateway(conf);
}
@AfterClass
public static void afterClass() throws Exception {
if (!runAfter) {
return;
}
stopGateway(conf);
tmpFolder.delete();
}
public static Injector startGateway(final CConfiguration conf) throws Exception {
// Set up our Guice injections
injector = Guice.createInjector(
Modules.override(
new AbstractModule() {
@Override
protected void configure() {
}
@SuppressWarnings("unused")
@Provides
@Named(Constants.Router.ADDRESS)
public final InetAddress providesHostname(CConfiguration cConf) {
return Networks.resolve(cConf.get
(Constants.Router.ADDRESS), new InetSocketAddress
("localhost", 0).getAddress());
}
},
new InMemorySecurityModule(),
new NotificationServiceRuntimeModule().getInMemoryModules(),
new AppFabricTestModule(conf)
).with(new AbstractModule() {
@Override
protected void configure() {
install(new StreamServiceRuntimeModule().getStandaloneModules());
install(new NamespaceClientRuntimeModule().getStandaloneModules());
// It's a bit hacky to add it here. Need to refactor these
// bindings out as it overlaps with
// AppFabricServiceModule
bind(LogReader.class).to(MockLogReader.class).in(Scopes.SINGLETON);
bind(StreamConsumerStateStoreFactory.class)
.to(LevelDBStreamConsumerStateStoreFactory.class).in(Singleton.class);
bind(StreamAdmin.class).to(FileStreamAdmin.class).in(Singleton.class);
bind(StreamConsumerFactory.class).to(LevelDBStreamFileConsumerFactory.class).in(Singleton.class);
bind(StreamFileWriterFactory.class).to(LocationStreamFileWriterFactory.class).in(Singleton.class);
}
})
);
txService = injector.getInstance(TransactionManager.class);
txService.startAndWait();
dsOpService = injector.getInstance(DatasetOpExecutor.class);
dsOpService.startAndWait();
datasetService = injector.getInstance(DatasetService.class);
datasetService.startAndWait();
appFabricServer = injector.getInstance(AppFabricServer.class);
appFabricServer.startAndWait();
metricsQueryService = injector.getInstance(MetricsQueryService.class);
metricsQueryService.startAndWait();
metricsCollectionService = injector.getInstance(MetricsCollectionService.class);
metricsCollectionService.startAndWait();
notificationService = injector.getInstance(NotificationService.class);
notificationService.startAndWait();
streamService = injector.getInstance(StreamService.class);
streamService.startAndWait();
namespaceAdmin = injector.getInstance(NamespaceAdmin.class);
namespaceAdmin.create(TEST_NAMESPACE_META1);
namespaceAdmin.create(TEST_NAMESPACE_META2);
// Restart handlers to check if they are resilient across restarts.
router = injector.getInstance(NettyRouter.class);
router.startAndWait();
Map<String, Integer> serviceMap = Maps.newHashMap();
for (Map.Entry<Integer, String> entry : router.getServiceLookup().getServiceMap().entrySet()) {
serviceMap.put(entry.getValue(), entry.getKey());
}
port = serviceMap.get(Constants.Service.GATEWAY);
return injector;
}
public static void stopGateway(CConfiguration conf) throws Exception {
namespaceAdmin.delete(Id.Namespace.from(TEST_NAMESPACE1));
namespaceAdmin.delete(Id.Namespace.from(TEST_NAMESPACE2));
namespaceAdmin.delete(Id.Namespace.DEFAULT);
streamService.stopAndWait();
notificationService.stopAndWait();
appFabricServer.stopAndWait();
metricsCollectionService.stopAndWait();
metricsQueryService.stopAndWait();
router.stopAndWait();
datasetService.stopAndWait();
dsOpService.stopAndWait();
txService.stopAndWait();
conf.clear();
}
public static Injector getInjector() {
return injector;
}
public static int getPort() {
return port;
}
public static Header getAuthHeader() {
return AUTH_HEADER;
}
public static URI getEndPoint(String path) throws URISyntaxException {
return new URI("http://" + hostname + ":" + port + path);
}
protected static void waitState(String programType, String appId, String programId, String state) throws Exception {
int trials = 0;
// it may take a while for workflow/mr to start...
while (trials++ < 20) {
String status = getState(programType, appId, programId);
if (status != null && state.equals(status)) {
break;
}
TimeUnit.SECONDS.sleep(1);
}
Assert.assertTrue(trials < 20);
}
protected static String getState(String programType, String appId, String programId) throws Exception {
HttpResponse response = GatewayFastTestsSuite.doGet(String.format("/v3/namespaces/default/apps/%s/%s/%s/status",
appId, programType, programId));
JsonObject status = GSON.fromJson(EntityUtils.toString(response.getEntity()), JsonObject.class);
if (status != null && status.has("status")) {
return status.get("status").getAsString();
}
return null;
}
}