/* * 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; } }