/* * Copyright © 2014-2016 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.test; import co.cask.cdap.api.Config; import co.cask.cdap.api.annotation.Beta; import co.cask.cdap.api.app.Application; import co.cask.cdap.api.dataset.DatasetAdmin; import co.cask.cdap.api.dataset.DatasetProperties; import co.cask.cdap.api.dataset.module.DatasetModule; import co.cask.cdap.api.metrics.MetricStore; import co.cask.cdap.api.metrics.MetricsCollectionService; import co.cask.cdap.api.plugin.PluginClass; import co.cask.cdap.app.guice.AppFabricServiceRuntimeModule; import co.cask.cdap.app.guice.AuthorizationModule; import co.cask.cdap.app.guice.InMemoryProgramRunnerModule; import co.cask.cdap.app.guice.ServiceStoreModules; import co.cask.cdap.common.conf.CConfiguration; import co.cask.cdap.common.conf.Constants; import co.cask.cdap.common.guice.ConfigModule; import co.cask.cdap.common.guice.DiscoveryRuntimeModule; import co.cask.cdap.common.guice.IOModule; import co.cask.cdap.common.guice.LocationRuntimeModule; 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.common.utils.OSDetector; import co.cask.cdap.data.runtime.DataFabricModules; import co.cask.cdap.data.runtime.DataSetServiceModules; import co.cask.cdap.data.runtime.DataSetsModules; import co.cask.cdap.data.runtime.LocationStreamFileWriterFactory; import co.cask.cdap.data.runtime.TransactionExecutorModule; import co.cask.cdap.data.stream.InMemoryStreamCoordinatorClient; import co.cask.cdap.data.stream.StreamAdminModules; import co.cask.cdap.data.stream.StreamCoordinatorClient; import co.cask.cdap.data.stream.StreamFileWriterFactory; import co.cask.cdap.data.stream.StreamViewHttpHandler; import co.cask.cdap.data.stream.service.BasicStreamWriterSizeCollector; import co.cask.cdap.data.stream.service.LocalStreamFileJanitorService; import co.cask.cdap.data.stream.service.StreamFetchHandler; import co.cask.cdap.data.stream.service.StreamFileJanitorService; import co.cask.cdap.data.stream.service.StreamHandler; import co.cask.cdap.data.stream.service.StreamWriterSizeCollector; import co.cask.cdap.data.view.ViewAdminModules; 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.explore.client.ExploreClient; import co.cask.cdap.explore.executor.ExploreExecutorService; import co.cask.cdap.explore.guice.ExploreClientModule; import co.cask.cdap.explore.guice.ExploreRuntimeModule; import co.cask.cdap.gateway.handlers.AuthorizationHandler; import co.cask.cdap.internal.app.runtime.schedule.SchedulerService; import co.cask.cdap.logging.guice.LoggingModules; import co.cask.cdap.metrics.guice.MetricsClientRuntimeModule; import co.cask.cdap.metrics.guice.MetricsHandlerModule; import co.cask.cdap.metrics.query.MetricsQueryService; import co.cask.cdap.notifications.feeds.guice.NotificationFeedServiceRuntimeModule; import co.cask.cdap.notifications.guice.NotificationServiceRuntimeModule; import co.cask.cdap.proto.Id; import co.cask.cdap.proto.NamespaceMeta; import co.cask.cdap.proto.artifact.AppRequest; import co.cask.cdap.proto.artifact.ArtifactRange; import co.cask.cdap.proto.id.ArtifactId; import co.cask.cdap.proto.id.InstanceId; import co.cask.cdap.proto.id.NamespaceId; import co.cask.cdap.proto.security.Action; import co.cask.cdap.proto.security.Principal; import co.cask.cdap.security.authorization.AuthorizerInstantiatorService; import co.cask.cdap.security.authorization.InvalidAuthorizerException; import co.cask.cdap.security.spi.authentication.SecurityRequestContext; import co.cask.cdap.security.spi.authorization.Authorizer; import co.cask.cdap.store.guice.NamespaceStoreModule; import co.cask.cdap.test.internal.ApplicationManagerFactory; import co.cask.cdap.test.internal.ArtifactManagerFactory; import co.cask.cdap.test.internal.DefaultApplicationManager; import co.cask.cdap.test.internal.DefaultArtifactManager; import co.cask.cdap.test.internal.DefaultStreamManager; import co.cask.cdap.test.internal.LocalStreamWriter; import co.cask.cdap.test.internal.StreamManagerFactory; import co.cask.tephra.TransactionManager; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableSet; import com.google.common.io.ByteStreams; import com.google.common.io.Closeables; import com.google.common.io.Files; import com.google.common.io.Resources; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.Provider; import com.google.inject.Scopes; import com.google.inject.Singleton; import com.google.inject.assistedinject.FactoryModuleBuilder; import com.google.inject.util.Modules; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.rules.TemporaryFolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.URL; import java.sql.Connection; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.jar.Manifest; /** * Base class to inherit from for unit-test. * It provides testing functionality for {@link co.cask.cdap.api.app.Application}. * To clean App Fabric state, you can use the {@link #clear} method. * <p> * Custom configurations for CDAP can be set by using {@link ClassRule} and {@link TestConfiguration}. * </p> * * @see TestConfiguration */ public class TestBase { private static final Logger LOG = LoggerFactory.getLogger(TestBase.class); @ClassRule public static final TemporaryFolder TMP_FOLDER = new TemporaryFolder(); @Deprecated @SuppressWarnings("unused") public static TemporaryFolder tmpFolder = TMP_FOLDER; private static CConfiguration cConf; private static int startCount; private static MetricsQueryService metricsQueryService; private static MetricsCollectionService metricsCollectionService; private static SchedulerService schedulerService; private static ExploreExecutorService exploreExecutorService; private static ExploreClient exploreClient; private static DatasetOpExecutor dsOpService; private static DatasetService datasetService; private static TransactionManager txService; private static StreamCoordinatorClient streamCoordinatorClient; private static MetricsManager metricsManager; private static TestManager testManager; private static NamespaceAdmin namespaceAdmin; private static AuthorizerInstantiatorService authorizerInstantiatorService; // This list is to record ApplicationManager create inside @Test method private static final List<ApplicationManager> applicationManagers = new ArrayList<>(); @BeforeClass public static void initialize() throws Exception { if (startCount++ > 0) { return; } File localDataDir = TMP_FOLDER.newFolder(); cConf = createCConf(localDataDir); org.apache.hadoop.conf.Configuration hConf = new org.apache.hadoop.conf.Configuration(); hConf.addResource("mapred-site-local.xml"); hConf.reloadConfiguration(); hConf.set(Constants.CFG_LOCAL_DATA_DIR, localDataDir.getAbsolutePath()); hConf.set(Constants.AppFabric.OUTPUT_DIR, cConf.get(Constants.AppFabric.OUTPUT_DIR)); hConf.set("hadoop.tmp.dir", new File(localDataDir, cConf.get(Constants.AppFabric.TEMP_DIR)).getAbsolutePath()); // Windows specific requirements if (OSDetector.isWindows()) { File tmpDir = TMP_FOLDER.newFolder(); File binDir = new File(tmpDir, "bin"); Assert.assertTrue(binDir.mkdirs()); copyTempFile("hadoop.dll", tmpDir); copyTempFile("winutils.exe", binDir); System.setProperty("hadoop.home.dir", tmpDir.getAbsolutePath()); System.load(new File(tmpDir, "hadoop.dll").getAbsolutePath()); } Injector injector = Guice.createInjector( createDataFabricModule(), new TransactionExecutorModule(), new DataSetsModules().getStandaloneModules(), new DataSetServiceModules().getInMemoryModules(), new ConfigModule(cConf, hConf), new IOModule(), new LocationRuntimeModule().getInMemoryModules(), new DiscoveryRuntimeModule().getInMemoryModules(), new AppFabricServiceRuntimeModule().getInMemoryModules(), new ServiceStoreModules().getInMemoryModules(), new InMemoryProgramRunnerModule(LocalStreamWriter.class), new AbstractModule() { @Override protected void configure() { bind(StreamHandler.class).in(Scopes.SINGLETON); bind(StreamFetchHandler.class).in(Scopes.SINGLETON); bind(StreamViewHttpHandler.class).in(Scopes.SINGLETON); bind(StreamFileJanitorService.class).to(LocalStreamFileJanitorService.class).in(Scopes.SINGLETON); bind(StreamWriterSizeCollector.class).to(BasicStreamWriterSizeCollector.class).in(Scopes.SINGLETON); bind(StreamCoordinatorClient.class).to(InMemoryStreamCoordinatorClient.class).in(Scopes.SINGLETON); bind(MetricsManager.class).toProvider(MetricsManagerProvider.class); } }, // todo: do we need handler? new MetricsHandlerModule(), new MetricsClientRuntimeModule().getInMemoryModules(), new LoggingModules().getInMemoryModules(), new ExploreRuntimeModule().getInMemoryModules(), new ExploreClientModule(), new NotificationFeedServiceRuntimeModule().getInMemoryModules(), new NotificationServiceRuntimeModule().getInMemoryModules(), new NamespaceClientRuntimeModule().getStandaloneModules(), new NamespaceStoreModule().getStandaloneModules(), new AuthorizationModule(), new AbstractModule() { @Override @SuppressWarnings("deprecation") protected void configure() { install(new FactoryModuleBuilder().implement(ApplicationManager.class, DefaultApplicationManager.class) .build(ApplicationManagerFactory.class)); install(new FactoryModuleBuilder().implement(ArtifactManager.class, DefaultArtifactManager.class) .build(ArtifactManagerFactory.class)); install(new FactoryModuleBuilder().implement(StreamManager.class, DefaultStreamManager.class) .build(StreamManagerFactory.class)); bind(TemporaryFolder.class).toInstance(TMP_FOLDER); bind(AuthorizationHandler.class).in(Scopes.SINGLETON); } } ); txService = injector.getInstance(TransactionManager.class); txService.startAndWait(); dsOpService = injector.getInstance(DatasetOpExecutor.class); dsOpService.startAndWait(); datasetService = injector.getInstance(DatasetService.class); datasetService.startAndWait(); metricsQueryService = injector.getInstance(MetricsQueryService.class); metricsQueryService.startAndWait(); metricsCollectionService = injector.getInstance(MetricsCollectionService.class); metricsCollectionService.startAndWait(); schedulerService = injector.getInstance(SchedulerService.class); schedulerService.startAndWait(); if (cConf.getBoolean(Constants.Explore.EXPLORE_ENABLED)) { exploreExecutorService = injector.getInstance(ExploreExecutorService.class); exploreExecutorService.startAndWait(); exploreClient = injector.getInstance(ExploreClient.class); } streamCoordinatorClient = injector.getInstance(StreamCoordinatorClient.class); streamCoordinatorClient.startAndWait(); testManager = injector.getInstance(UnitTestManager.class); metricsManager = injector.getInstance(MetricsManager.class); authorizerInstantiatorService = injector.getInstance(AuthorizerInstantiatorService.class); authorizerInstantiatorService.startAndWait(); // This is needed so the logged-in user can successfully create the default namespace if (cConf.getBoolean(Constants.Security.Authorization.ENABLED)) { InstanceId instance = new InstanceId(cConf.get(Constants.INSTANCE_NAME)); Principal principal = new Principal(SecurityRequestContext.getUserId(), Principal.PrincipalType.USER); authorizerInstantiatorService.get().grant(instance, principal, ImmutableSet.of(Action.ADMIN)); } namespaceAdmin = injector.getInstance(NamespaceAdmin.class); namespaceAdmin.create(NamespaceMeta.DEFAULT); } private static TestManager getTestManager() { Preconditions.checkState(testManager != null, "Test framework is not yet running"); return testManager; } @Before public void beforeTest() throws Exception { applicationManagers.clear(); } /** * By default after each test finished, it will stop all apps started during the test. * Sub-classes can override this method to provide different behavior. */ @After public void afterTest() throws Exception { for (ApplicationManager manager : applicationManagers) { manager.stopAll(); } } private static class MetricsManagerProvider implements Provider<MetricsManager> { private final MetricStore metricStore; @Inject @SuppressWarnings("unused") private MetricsManagerProvider(MetricStore metricStore) { this.metricStore = metricStore; } @Override public MetricsManager get() { return new MetricsManager(metricStore); } } private static CConfiguration createCConf(File localDataDir) throws IOException { CConfiguration cConf = CConfiguration.create(); // Setup defaults that can be overridden by user cConf.setBoolean(Constants.Explore.EXPLORE_ENABLED, true); cConf.setBoolean(Constants.Explore.START_ON_DEMAND, true); // Setup test case specific configurations. // The system properties are usually setup by TestConfiguration class using @ClassRule for (String key : System.getProperties().stringPropertyNames()) { if (key.startsWith(TestConfiguration.PROPERTY_PREFIX)) { String value = System.getProperty(key); cConf.set(key.substring(TestConfiguration.PROPERTY_PREFIX.length()), System.getProperty(key)); LOG.info("Custom configuration set: {} = {}", key, value); } } // These configurations cannot be overridden by user // configure all services except for router to bind to localhost String localhost = InetAddress.getLoopbackAddress().getHostAddress(); cConf.set(Constants.AppFabric.SERVER_ADDRESS, localhost); cConf.set(Constants.Transaction.Container.ADDRESS, localhost); cConf.set(Constants.Dataset.Manager.ADDRESS, localhost); cConf.set(Constants.Dataset.Executor.ADDRESS, localhost); cConf.set(Constants.Stream.ADDRESS, localhost); cConf.set(Constants.Metrics.ADDRESS, localhost); cConf.set(Constants.Metrics.SERVER_ADDRESS, localhost); cConf.set(Constants.MetricsProcessor.ADDRESS, localhost); cConf.set(Constants.LogSaver.ADDRESS, localhost); cConf.set(Constants.Security.AUTH_SERVER_BIND_ADDRESS, localhost); cConf.set(Constants.Explore.SERVER_ADDRESS, localhost); cConf.set(Constants.Metadata.SERVICE_BIND_ADDRESS, localhost); cConf.set(Constants.Metrics.SERVER_PORT, Integer.toString(Networks.getRandomPort())); cConf.set(Constants.CFG_LOCAL_DATA_DIR, localDataDir.getAbsolutePath()); cConf.setBoolean(Constants.Dangerous.UNRECOVERABLE_RESET, true); cConf.set(Constants.Explore.LOCAL_DATA_DIR, TMP_FOLDER.newFolder("hive").getAbsolutePath()); return cConf; } private static Module createDataFabricModule() { return Modules.override(new DataFabricModules().getInMemoryModules(), new ViewAdminModules().getInMemoryModules(), new StreamAdminModules().getInMemoryModules()) .with(new AbstractModule() { @Override protected void configure() { 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); } }); } private static void copyTempFile(String infileName, File outDir) throws IOException { URL url = TestBase.class.getClassLoader().getResource(infileName); if (url == null) { throw new IOException("Failed to get resource for " + infileName); } File outFile = new File(outDir, infileName); ByteStreams.copy(Resources.newInputStreamSupplier(url), Files.newOutputStreamSupplier(outFile)); } @AfterClass public static void finish() throws Exception { if (--startCount != 0) { return; } namespaceAdmin.delete(Id.Namespace.DEFAULT); authorizerInstantiatorService.stopAndWait(); streamCoordinatorClient.stopAndWait(); metricsQueryService.stopAndWait(); metricsCollectionService.startAndWait(); schedulerService.stopAndWait(); if (exploreClient != null) { Closeables.closeQuietly(exploreClient); } if (exploreExecutorService != null) { exploreExecutorService.stopAndWait(); } datasetService.stopAndWait(); dsOpService.stopAndWait(); txService.stopAndWait(); } protected MetricsManager getMetricsManager() { return metricsManager; } /** * Creates a Namespace. * * @param namespace the namespace to create * @deprecated since 3.4.0. Use {@link #getNamespaceAdmin()} to perform namespace operations instead. */ @Deprecated protected static void createNamespace(Id.Namespace namespace) throws Exception { getTestManager().createNamespace(new NamespaceMeta.Builder().setName(namespace).build()); } /** * Deletes a Namespace. * * @param namespace the namespace to delete * @deprecated since 3.4.0. Use {@link #getNamespaceAdmin()} to perform namespace operations instead. */ @Deprecated protected static void deleteNamespace(Id.Namespace namespace) throws Exception { getTestManager().deleteNamespace(namespace); } /** * Deploys an {@link Application}. The {@link co.cask.cdap.api.flow.Flow Flows} and * other programs defined in the application must be in the same or children package as the application. * * @param applicationClz The application class * @return An {@link ApplicationManager} to manage the deployed application. */ protected static ApplicationManager deployApplication(Id.Namespace namespace, Class<? extends Application> applicationClz, File... bundleEmbeddedJars) { return deployApplication(namespace, applicationClz, null, bundleEmbeddedJars); } protected static ApplicationManager deployApplication(Id.Namespace namespace, Class<? extends Application> applicationClz, Config appConfig, File... bundleEmbeddedJars) { ApplicationManager applicationManager = getTestManager().deployApplication(namespace, applicationClz, appConfig, bundleEmbeddedJars); applicationManagers.add(applicationManager); return applicationManager; } /** * Deploys an {@link Application}. The {@link co.cask.cdap.api.flow.Flow Flows} and * other programs defined in the application must be in the same or children package as the application. * * @param applicationClz The application class * @return An {@link ApplicationManager} to manage the deployed application. */ protected static ApplicationManager deployApplication(Class<? extends Application> applicationClz, File... bundleEmbeddedJars) { return deployApplication(Id.Namespace.DEFAULT, applicationClz, bundleEmbeddedJars); } protected static ApplicationManager deployApplication(Class<? extends Application> applicationClz, Config appConfig, File... bundleEmbeddedJars) { return deployApplication(Id.Namespace.DEFAULT, applicationClz, appConfig, bundleEmbeddedJars); } /** * Deploys an {@link Application}. The application artifact must already exist. * * @param appId the id of the application to create * @param appRequest the application create or update request * @return An {@link ApplicationManager} to manage the deployed application */ protected static ApplicationManager deployApplication(Id.Application appId, AppRequest appRequest) throws Exception { return getTestManager().deployApplication(appId, appRequest); } /** * Add the specified artifact. * * @param artifactId the id of the artifact to add * @param artifactFile the contents of the artifact. Must be a valid jar file containing apps or plugins * @deprecated since 3.4.0. Use {@link #addArtifact(ArtifactId, File)} */ @Deprecated protected static void addArtifact(Id.Artifact artifactId, File artifactFile) throws Exception { addArtifact(artifactId.toEntityId(), artifactFile); } /** * Add the specified artifact. * * @param artifactId the id of the artifact to add * @param artifactFile the contents of the artifact. Must be a valid jar file containing apps or plugins * @throws Exception */ protected static ArtifactManager addArtifact(ArtifactId artifactId, File artifactFile) throws Exception { return getTestManager().addArtifact(artifactId, artifactFile); } /** * Build an application artifact from the specified class and then add it. * * @param artifactId the id of the artifact to add * @param appClass the application class to build the artifact from * @deprecated since 3.4.0. Use {@link #addArtifact(ArtifactId, File)}. */ @Deprecated protected static void addAppArtifact(Id.Artifact artifactId, Class<?> appClass) throws Exception { getTestManager().addAppArtifact(artifactId, appClass); } /** * Build an application artifact from the specified class and then add it. * * @param artifactId the id of the artifact to add * @param appClass the application class to build the artifact from * @return an {@link ArtifactManager} to manage the added artifact */ protected static ArtifactManager addAppArtifact(ArtifactId artifactId, Class<?> appClass) throws Exception { return getTestManager().addAppArtifact(artifactId, appClass); } /** * Build an application artifact from the specified class and then add it. * * @param artifactId the id of the artifact to add * @param appClass the application class to build the artifact from * @param exportPackages the packages to export and place in the manifest of the jar to build. This should include * packages that contain classes that plugins for the application will implement. * @deprecated since 3.4.0. Use {@link #addAppArtifact(ArtifactId, Class, String...)} */ @Deprecated protected static void addAppArtifact(Id.Artifact artifactId, Class<?> appClass, String... exportPackages) throws Exception { getTestManager().addAppArtifact(artifactId, appClass, exportPackages); } /** * Build an application artifact from the specified class and then add it. * * @param artifactId the id of the artifact to add * @param appClass the application class to build the artifact from * @param exportPackages the packages to export and place in the manifest of the jar to build. This should include * packages that contain classes that plugins for the application will implement. * @return an {@link ArtifactManager} to manage the added artifact */ protected static ArtifactManager addAppArtifact(ArtifactId artifactId, Class<?> appClass, String... exportPackages) throws Exception { return getTestManager().addAppArtifact(artifactId, appClass, exportPackages); } /** * Build an application artifact from the specified class and then add it. * * @param artifactId the id of the artifact to add * @param appClass the application class to build the artifact from * @param manifest the manifest to use when building the jar * @deprecated since 3.4.0. Use {@link #addAppArtifact(ArtifactId, Class, Manifest)} */ @Deprecated protected static void addAppArtifact(Id.Artifact artifactId, Class<?> appClass, Manifest manifest) throws Exception { getTestManager().addAppArtifact(artifactId, appClass, manifest); } /** * Build an application artifact from the specified class and then add it. * * @param artifactId the id of the artifact to add * @param appClass the application class to build the artifact from * @param manifest the manifest to use when building the jar * @return an {@link ArtifactManager} to manage the added artifact */ protected static ArtifactManager addAppArtifact(ArtifactId artifactId, Class<?> appClass, Manifest manifest) throws Exception { return getTestManager().addAppArtifact(artifactId, appClass, manifest); } /** * Build an artifact from the specified plugin classes and then add it. The * jar created will include all classes in the same package as the give classes, plus any dependencies of the * given classes. If another plugin in the same package as the given plugin requires a different set of dependent * classes, you must include both plugins. For example, suppose you have two plugins, * com.company.myapp.functions.functionX and com.company.myapp.function.functionY, with functionX having * one set of dependencies and functionY having another set of dependencies. If you only add functionX, functionY * will also be included in the created jar since it is in the same package. However, only functionX's dependencies * will be traced and added to the jar, so you will run into issues when the platform tries to register functionY. * In this scenario, you must be certain to include specify both functionX and functionY when calling this method. * * @param artifactId the id of the artifact to add * @param parent the parent artifact it extends * @param pluginClass the plugin class to build the jar from * @param pluginClasses any additional plugin classes that should be included in the jar * @deprecated since 3.4.0. Use {@link #addPluginArtifact(ArtifactId, ArtifactId, Class, Class[])} */ @Deprecated protected static void addPluginArtifact(Id.Artifact artifactId, Id.Artifact parent, Class<?> pluginClass, Class<?>... pluginClasses) throws Exception { getTestManager().addPluginArtifact(artifactId, parent, pluginClass, pluginClasses); } /** * Build an artifact from the specified plugin classes and then add it. The * jar created will include all classes in the same package as the give classes, plus any dependencies of the * given classes. If another plugin in the same package as the given plugin requires a different set of dependent * classes, you must include both plugins. For example, suppose you have two plugins, * com.company.myapp.functions.functionX and com.company.myapp.function.functionY, with functionX having * one set of dependencies and functionY having another set of dependencies. If you only add functionX, functionY * will also be included in the created jar since it is in the same package. However, only functionX's dependencies * will be traced and added to the jar, so you will run into issues when the platform tries to register functionY. * In this scenario, you must be certain to include specify both functionX and functionY when calling this method. * * @param artifactId the id of the artifact to add * @param parent the parent artifact it extends * @param pluginClass the plugin class to build the jar from * @param pluginClasses any additional plugin classes that should be included in the jar * @return {@link ArtifactManager} to manage the added plugin artifact */ protected static ArtifactManager addPluginArtifact(ArtifactId artifactId, ArtifactId parent, Class<?> pluginClass, Class<?>... pluginClasses) throws Exception { return getTestManager().addPluginArtifact(artifactId, parent, pluginClass, pluginClasses); } /** * Build an artifact from the specified plugin classes and then add it. The * jar created will include all classes in the same package as the give classes, plus any dependencies of the * given classes. If another plugin in the same package as the given plugin requires a different set of dependent * classes, you must include both plugins. For example, suppose you have two plugins, * com.company.myapp.functions.functionX and com.company.myapp.function.functionY, with functionX having * one set of dependencies and functionY having another set of dependencies. If you only add functionX, functionY * will also be included in the created jar since it is in the same package. However, only functionX's dependencies * will be traced and added to the jar, so you will run into issues when the platform tries to register functionY. * In this scenario, you must be certain to include specify both functionX and functionY when calling this method. * * @param artifactId the id of the artifact to add * @param parent the parent artifact it extends * @param additionalPlugins any plugin classes that need to be explicitly declared because they cannot be found * by inspecting the jar. This is true for 3rd party plugins, such as jdbc drivers * @param pluginClass the plugin class to build the jar from * @param pluginClasses any additional plugin classes that should be included in the jar * @deprecated since 3.4.0. Use * {@link #addPluginArtifact(ArtifactId, ArtifactId, Set, Class, Class[])} */ @Deprecated protected static void addPluginArtifact(Id.Artifact artifactId, Id.Artifact parent, Set<PluginClass> additionalPlugins, Class<?> pluginClass, Class<?>... pluginClasses) throws Exception { getTestManager().addPluginArtifact(artifactId, parent, additionalPlugins, pluginClass, pluginClasses); } /** * Build an artifact from the specified plugin classes and then add it. The * jar created will include all classes in the same package as the give classes, plus any dependencies of the * given classes. If another plugin in the same package as the given plugin requires a different set of dependent * classes, you must include both plugins. For example, suppose you have two plugins, * com.company.myapp.functions.functionX and com.company.myapp.function.functionY, with functionX having * one set of dependencies and functionY having another set of dependencies. If you only add functionX, functionY * will also be included in the created jar since it is in the same package. However, only functionX's dependencies * will be traced and added to the jar, so you will run into issues when the platform tries to register functionY. * In this scenario, you must be certain to include specify both functionX and functionY when calling this method. * * @param artifactId the id of the artifact to add * @param parent the parent artifact it extends * @param additionalPlugins any plugin classes that need to be explicitly declared because they cannot be found * by inspecting the jar. This is true for 3rd party plugins, such as jdbc drivers * @param pluginClass the plugin class to build the jar from * @param pluginClasses any additional plugin classes that should be included in the jar * @return an {@link ArtifactManager} to manage the added plugin artifact */ protected static ArtifactManager addPluginArtifact(ArtifactId artifactId, ArtifactId parent, Set<PluginClass> additionalPlugins, Class<?> pluginClass, Class<?>... pluginClasses) throws Exception { return getTestManager().addPluginArtifact(artifactId, parent, additionalPlugins, pluginClass, pluginClasses); } /** * Build an artifact from the specified plugin classes and then add it. The * jar created will include all classes in the same package as the give classes, plus any dependencies of the * given classes. If another plugin in the same package as the given plugin requires a different set of dependent * classes, you must include both plugins. For example, suppose you have two plugins, * com.company.myapp.functions.functionX and com.company.myapp.function.functionY, with functionX having * one set of dependencies and functionY having another set of dependencies. If you only add functionX, functionY * will also be included in the created jar since it is in the same package. However, only functionX's dependencies * will be traced and added to the jar, so you will run into issues when the platform tries to register functionY. * In this scenario, you must be certain to include specify both functionX and functionY when calling this method. * * @param artifactId the id of the artifact to add * @param parentArtifacts the parent artifacts it extends * @param pluginClass the plugin class to build the jar from * @param pluginClasses any additional plugin classes that should be included in the jar * @deprecated since 3.4.0. Use {@link #addPluginArtifact(ArtifactId, Set, Class, Class[])} */ @Deprecated protected static void addPluginArtifact(Id.Artifact artifactId, Set<ArtifactRange> parentArtifacts, Class<?> pluginClass, Class<?>... pluginClasses) throws Exception { getTestManager().addPluginArtifact(artifactId, parentArtifacts, pluginClass, pluginClasses); } /** * Build an artifact from the specified plugin classes and then add it. The * jar created will include all classes in the same package as the give classes, plus any dependencies of the * given classes. If another plugin in the same package as the given plugin requires a different set of dependent * classes, you must include both plugins. For example, suppose you have two plugins, * com.company.myapp.functions.functionX and com.company.myapp.function.functionY, with functionX having * one set of dependencies and functionY having another set of dependencies. If you only add functionX, functionY * will also be included in the created jar since it is in the same package. However, only functionX's dependencies * will be traced and added to the jar, so you will run into issues when the platform tries to register functionY. * In this scenario, you must be certain to include specify both functionX and functionY when calling this method. * * @param artifactId the id of the artifact to add * @param parentArtifacts the parent artifacts it extends * @param pluginClass the plugin class to build the jar from * @param pluginClasses any additional plugin classes that should be included in the jar * @return an {@link ArtifactManager} to manage the added plugin artifact */ protected static ArtifactManager addPluginArtifact(ArtifactId artifactId, Set<ArtifactRange> parentArtifacts, Class<?> pluginClass, Class<?>... pluginClasses) throws Exception { return getTestManager().addPluginArtifact(artifactId, parentArtifacts, pluginClass, pluginClasses); } /** * Clear the state of app fabric, by removing all deployed applications, Datasets and Streams. * This method could be called between two unit tests, to make them independent. */ protected static void clear() { try { getTestManager().clear(); } catch (Exception e) { // Unchecked exception to maintain compatibility until we remove this method throw Throwables.propagate(e); } } /** * Deploys {@link DatasetModule}. * * @param moduleName name of the module * @param datasetModule module class * @throws Exception */ protected static void deployDatasetModule(Id.Namespace namespace, String moduleName, Class<? extends DatasetModule> datasetModule) throws Exception { getTestManager().deployDatasetModule(namespace, moduleName, datasetModule); } /** * Deploys {@link DatasetModule}. * * @param moduleName name of the module * @param datasetModule module class * @throws Exception */ protected static void deployDatasetModule(String moduleName, Class<? extends DatasetModule> datasetModule) throws Exception { deployDatasetModule(Id.Namespace.DEFAULT, moduleName, datasetModule); } /** * Adds an instance of a dataset. * * @param namespace namespace for the dataset * @param datasetTypeName dataset type name * @param datasetInstanceName instance name * @param props properties * @param <T> type of the dataset admin */ protected static <T extends DatasetAdmin> T addDatasetInstance(Id.Namespace namespace, String datasetTypeName, String datasetInstanceName, DatasetProperties props) throws Exception { return getTestManager().addDatasetInstance(namespace, datasetTypeName, datasetInstanceName, props); } /** * Adds an instance of a dataset. * * @param datasetTypeName dataset type name * @param datasetInstanceName instance name * @param props properties * @param <T> type of the dataset admin */ protected static <T extends DatasetAdmin> T addDatasetInstance(String datasetTypeName, String datasetInstanceName, DatasetProperties props) throws Exception { return addDatasetInstance(Id.Namespace.DEFAULT, datasetTypeName, datasetInstanceName, props); } /** * Adds an instance of dataset. * * @param namespace namespace for the dataset * @param datasetTypeName dataset type name * @param datasetInstanceName instance name * @param <T> type of the dataset admin */ protected final <T extends DatasetAdmin> T addDatasetInstance(Id.Namespace namespace, String datasetTypeName, String datasetInstanceName) throws Exception { return addDatasetInstance(namespace, datasetTypeName, datasetInstanceName, DatasetProperties.EMPTY); } /** * Adds an instance of dataset. * * @param datasetTypeName dataset type name * @param datasetInstanceName instance name * @param <T> type of the dataset admin */ protected final <T extends DatasetAdmin> T addDatasetInstance(String datasetTypeName, String datasetInstanceName) throws Exception { return addDatasetInstance(Id.Namespace.DEFAULT, datasetTypeName, datasetInstanceName, DatasetProperties.EMPTY); } /** * Gets Dataset manager of Dataset instance of type {@literal <}T>. * * @param namespace namespace for the dataset * @param datasetInstanceName instance name of dataset * @return Dataset Manager of Dataset instance of type <T> * @throws Exception */ protected final <T> DataSetManager<T> getDataset(Id.Namespace namespace, String datasetInstanceName) throws Exception { return getTestManager().getDataset(namespace, datasetInstanceName); } /** * Gets Dataset manager of Dataset instance of type {@literal <}T>. * * @param datasetInstanceName instance name of dataset * @return Dataset Manager of Dataset instance of type {@literal <}T> * @throws Exception */ protected final <T> DataSetManager<T> getDataset(String datasetInstanceName) throws Exception { return getDataset(Id.Namespace.DEFAULT, datasetInstanceName); } /** * Returns a JDBC connection that allows the running of SQL queries over data sets. * * @param namespace namespace for the connection */ protected final Connection getQueryClient(Id.Namespace namespace) throws Exception { if (!cConf.getBoolean(Constants.Explore.EXPLORE_ENABLED)) { throw new UnsupportedOperationException("Explore service is disabled. QueryClient not supported."); } return getTestManager().getQueryClient(namespace); } /** * Returns a JDBC connection that allows the running of SQL queries over data sets. */ protected final Connection getQueryClient() throws Exception { return getQueryClient(Id.Namespace.DEFAULT); } /** * Returns a {@link StreamManager} for the specified stream in the default namespace * * @param streamName the specified stream * @return {@link StreamManager} for the specified stream in the default namespace */ protected final StreamManager getStreamManager(String streamName) { return getStreamManager(Id.Namespace.DEFAULT, streamName); } /** * Returns a {@link StreamManager} for the specified stream in the specified namespace * * @param namespace namespace for the stream * @param streamName the specified stream * @return {@link StreamManager} for the specified stream in the specified namespace */ protected final StreamManager getStreamManager(Id.Namespace namespace, String streamName) { return getTestManager().getStreamManager(Id.Stream.from(namespace, streamName)); } protected TransactionManager getTxService() { return txService; } /** * Returns a {@link NamespaceAdmin} to interact with namespaces. */ protected static NamespaceAdmin getNamespaceAdmin() { return namespaceAdmin; } /** * Returns an {@link Authorizer} for performing authorization operations. */ @Beta protected static Authorizer getAuthorizer() throws IOException, InvalidAuthorizerException { return authorizerInstantiatorService.get(); } /** * Returns the {@link CConfiguration} used in tests. */ protected static CConfiguration getConfiguration() { return cConf; } /** * Deletes all applications in the specified namespace. * * @param namespaceId the namespace from which to delete all applications */ protected static void deleteAllApplications(NamespaceId namespaceId) throws Exception { getTestManager().deleteAllApplications(namespaceId); } }