/*
* 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.AbstractApplication;
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.plugin.PluginClass;
import co.cask.cdap.common.namespace.NamespaceAdmin;
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.ApplicationId;
import co.cask.cdap.proto.id.ArtifactId;
import co.cask.cdap.proto.id.NamespaceId;
import java.io.File;
import java.sql.Connection;
import java.util.Set;
import java.util.jar.Manifest;
import javax.annotation.Nullable;
/**
* Class that provides utility methods for writing tests for CDAP Applications.
*/
public interface TestManager {
/**
* 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 namespace The namespace to deploy to
* @param applicationClz The application class
* @return An {@link ApplicationManager} to manage the deployed application.
*/
ApplicationManager deployApplication(Id.Namespace namespace,
Class<? extends Application> applicationClz, File... bundleEmbeddedJars);
/**
* Deploys an {@link Application}.
*
* @param namespace The namespace to deploy to
* @param applicationClz The application class
* @param configObject Configuration object to be used during deployment and can be accessed
* in {@link Application#configure} via {@link AbstractApplication#getConfig}
* @return An {@link ApplicationManager} to manage the deployed application.
*/
ApplicationManager deployApplication(Id.Namespace namespace, Class<? extends Application> applicationClz,
@Nullable Config configObject, File... bundleEmbeddedJars);
/**
* Deploys an {@link Application}.
*
* @param appId the id of the application to create
* @param appRequest the app create or update request that includes the artifact to create the app from and any config
* to pass to the application.
* @return An {@link ApplicationManager} to manage the deployed application.
*/
ApplicationManager deployApplication(Id.Application appId, AppRequest appRequest) throws Exception;
/**
* Gets an Application Manager for an {@link Application}.
*
* @param appId the id of deployed application
* @return An {@link ApplicationManager} to manage the deployed application.
*/
ApplicationManager getApplicationManager(ApplicationId appId) throws Exception;
/**
* Adds 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
void addArtifact(Id.Artifact artifactId, File artifactFile) throws Exception;
/**
* Adds 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
* @return an {@link ArtifactManager} to manage the added artifact
*/
ArtifactManager addArtifact(ArtifactId artifactId, File artifactFile) throws Exception;
/**
* Builds an application artifact from the specified class and then adds 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 #addAppArtifact(ArtifactId, Class)}
*/
@Deprecated
void addAppArtifact(Id.Artifact artifactId, Class<?> appClass) throws Exception;
/**
* Builds an application artifact from the specified class and then adds it.
*
* @param artifactId the id of the artifact to add
* @param appClass the application class to build the artifact from
* @return an {@link ArtifactManager} for managing the added app artifact
*/
ArtifactManager addAppArtifact(ArtifactId artifactId, Class<?> appClass) throws Exception;
/**
* Builds an application artifact from the specified class and then adds 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...)} instead
*/
@Deprecated
void addAppArtifact(Id.Artifact artifactId, Class<?> appClass, String... exportPackages) throws Exception;
/**
* Builds an application artifact from the specified class and then adds 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 app artifact
*/
ArtifactManager addAppArtifact(ArtifactId artifactId, Class<?> appClass,
String... exportPackages) throws Exception;
/**
* Builds an application artifact from the specified class and then adds 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)} instead
*/
@Deprecated
void addAppArtifact(Id.Artifact artifactId, Class<?> appClass, Manifest manifest) throws Exception;
/**
* Builds an application artifact from the specified class and then adds 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 app artifact
*/
ArtifactManager addAppArtifact(ArtifactId artifactId, Class<?> appClass,
Manifest manifest) throws Exception;
/**
* Builds an artifact from the specified plugin classes and then adds 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
void addPluginArtifact(Id.Artifact artifactId, Id.Artifact parent,
Class<?> pluginClass, Class<?>... pluginClasses) throws Exception;
/**
* Builds an artifact from the specified plugin classes and then adds 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 an {@link ArtifactManager} for managing the added artifact
*/
ArtifactManager addPluginArtifact(ArtifactId artifactId, ArtifactId parent,
Class<?> pluginClass, Class<?>... pluginClasses) throws Exception;
/**
* Builds an artifact from the specified plugin classes and then adds 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 parents 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[])}
*/
void addPluginArtifact(Id.Artifact artifactId, Set<ArtifactRange> parents,
Class<?> pluginClass, Class<?>... pluginClasses) throws Exception;
/**
* Builds an artifact from the specified plugin classes and then adds 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 parents 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
*/
ArtifactManager addPluginArtifact(ArtifactId artifactId, Set<ArtifactRange> parents,
Class<?> pluginClass, Class<?>... pluginClasses) throws Exception;
/**
* Builds an artifact from the specified plugin classes and then adds 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
void addPluginArtifact(Id.Artifact artifactId, Id.Artifact parent,
@Nullable Set<PluginClass> additionalPlugins,
Class<?> pluginClass, Class<?>... pluginClasses) throws Exception;
/**
* Builds an artifact from the specified plugin classes and then adds 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 this artifact
*/
ArtifactManager addPluginArtifact(ArtifactId artifactId, ArtifactId parent,
@Nullable Set<PluginClass> additionalPlugins,
Class<?> pluginClass, Class<?>... pluginClasses) throws Exception;
/**
* Builds an artifact from the specified plugin classes and then adds 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 parents the parent artifacts 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, Set, Set, Class, Class[])}
*/
void addPluginArtifact(Id.Artifact artifactId, Set<ArtifactRange> parents,
@Nullable Set<PluginClass> additionalPlugins,
Class<?> pluginClass, Class<?>... pluginClasses) throws Exception;
/**
* Builds an artifact from the specified plugin classes and then adds 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 parents the parent artifacts 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 {@link ArtifactManager} to manage the added plugin artifact
*/
ArtifactManager addPluginArtifact(ArtifactId artifactId, Set<ArtifactRange> parents,
@Nullable Set<PluginClass> additionalPlugins,
Class<?> pluginClass, Class<?>... pluginClasses) throws Exception;
/**
* Deletes the specified artifact.
*
* @param artifactId the id of the artifact to delete
* @deprecated since 3.4.0. Use {@link ArtifactManager#delete()} instead
*/
@Deprecated
void deleteArtifact(Id.Artifact artifactId) throws Exception;
/**
* 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.
*/
void clear() throws Exception;
/**
* Deploys {@link DatasetModule}.
*
* @param namespace namespace to deploy the dataset module to
* @param moduleName name of the module
* @param datasetModule module class
* @throws Exception
*/
@Beta
void deployDatasetModule(Id.Namespace namespace, String moduleName, Class<? extends DatasetModule> datasetModule)
throws Exception;
/**
* Adds an instance of a dataset.
*
* @param namespace namespace of the dataset
* @param datasetTypeName dataset type name
* @param datasetInstanceName instance name
* @param props properties
* @param <T> type of the dataset admin
*/
@Beta
<T extends DatasetAdmin> T addDatasetInstance(Id.Namespace namespace,
String datasetTypeName, String datasetInstanceName,
DatasetProperties props) throws Exception;
/**
* Adds an instance of dataset.
*
* @param namespace namespace of the dataset
* @param datasetTypeName dataset type name
* @param datasetInstanceName instance name
* @param <T> type of the dataset admin
*/
@Beta
<T extends DatasetAdmin> T addDatasetInstance(Id.Namespace namespace,
String datasetTypeName, String datasetInstanceName) throws Exception;
/**
* Gets Dataset manager of Dataset instance of type {@literal <}T>.
*
* @param namespace namespace of the dataset
* @param datasetInstanceName instance name of dataset
* @return Dataset Manager of Dataset instance of type {@literal <}T>
* @throws Exception
*/
@Beta
<T> DataSetManager<T> getDataset(Id.Namespace namespace, String datasetInstanceName) throws Exception;
/**
* @param namespace namespace to interact within
* @return a JDBC connection that allows the running of SQL queries over data sets
*/
@Beta
Connection getQueryClient(Id.Namespace namespace) throws Exception;
/**
* Creates a namespace.
*
* @param namespaceMeta the namespace to create
* @deprecated since 3.4.0. Use {@link NamespaceAdmin} exposed by TestBase for namespace operations.
*/
@Deprecated
void createNamespace(NamespaceMeta namespaceMeta) throws Exception;
/**
* Deletes a namespace.
*
* @param namespace the namespace to delete
* @deprecated since 3.4.0. Use {@link NamespaceAdmin} exposed by TestBase for namespace operations.
*/
@Deprecated
void deleteNamespace(Id.Namespace namespace) throws Exception;
/**
* Returns a {@link StreamManager} for the specified {@link Id.Stream}.
*/
StreamManager getStreamManager(Id.Stream streamId);
/**
* Removes all apps in the specified namespace.
*
* @param namespaceId the namespace from which to remove all apps
*/
void deleteAllApplications(NamespaceId namespaceId) throws Exception;
}