
org.fabric3.runtime.maven.itest.Fabric3ITestMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fabric3-itest-plugin Show documentation
Show all versions of fabric3-itest-plugin Show documentation
Fabric3 Maven Runtime plugin
The newest version!
/*
* Fabric3
* Copyright (c) 2009-2015 Metaform Systems
*
* 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.
*
* Portions originally based on Apache Tuscany 2007
* licensed under the Apache 2.0 license.
*/
package org.fabric3.runtime.maven.itest;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.DependencyResolutionException;
import org.fabric3.api.host.Names;
import org.fabric3.api.host.classloader.MaskingClassLoader;
import org.fabric3.api.host.contribution.ContributionNotFoundException;
import org.fabric3.api.host.contribution.ContributionService;
import org.fabric3.api.host.contribution.ContributionSource;
import org.fabric3.api.host.contribution.FileContributionSource;
import org.fabric3.api.host.contribution.InstallException;
import org.fabric3.api.host.contribution.StoreException;
import org.fabric3.api.host.domain.DeploymentException;
import org.fabric3.api.host.domain.Domain;
import org.fabric3.api.host.runtime.InitializationException;
import org.fabric3.api.host.util.FileHelper;
import org.fabric3.plugin.Fabric3PluginException;
import org.fabric3.plugin.api.runtime.PluginRuntime;
import org.fabric3.plugin.resolver.Resolver;
import org.fabric3.plugin.runtime.PluginBootConfiguration;
import org.fabric3.plugin.runtime.PluginConstants;
import org.fabric3.plugin.util.ClassLoaderHelper;
/**
* Instantiates a Fabric3 plugin runtime and deploys Maven modules as contributions for integration testing.
*
* @goal test
* @phase integration-test
* @execute phase="integration-test"
*/
public class Fabric3ITestMojo extends AbstractMojo {
private static final String CLEAN = "fabric3.extensions.dependencies.cleanup";
static {
// This static block is used to optionally clean the temporary directory between test runs. A static block is used as the iTest plugin may
// be instantiated multiple times during a run.
boolean clearTmp = Boolean.valueOf(System.getProperty(CLEAN, "false"));
if (clearTmp) {
clearTempFiles();
}
}
public static final String FABRIC3_GROUP_ID = "org.fabric3";
/**
* POM
*
* @parameter expression="${project}"
* @readonly
* @required
*/
protected MavenProject project;
/**
* The optional target namespace of the composite to activate.
*
* @parameter
*/
public String compositeNamespace = "urn:fabric3.org";
/**
* The local name of the composite to activate.
*
* @parameter
*/
public String compositeName = "TestComposite";
/**
* The project build directory.
*
* @parameter expression="${project.build.directory}"
*/
public File buildDirectory;
/**
* Do not run if this is set to true. This usage is consistent with the surefire plugin.
*
* @parameter expression="${maven.test.skip}"
*/
public boolean skip;
/**
* When set to true, this will ignore test failures.
*
* @parameter expression="${maven.test.ignoreTestFailures}"
*/
public boolean ignoreTestFailures;
/**
* The directory where reports will be written.
*
* @parameter expression="${project.build.directory}/surefire-reports"
*/
public File reportsDirectory;
/**
* Whether to trim the stack trace in the reports to just the lines within the test, or show the full trace.
*
* @parameter expression="${trimStackTrace}" default-value="true"
*/
public boolean trimStackTrace;
/**
* The version of the runtime to use.
*
* @parameter
*/
public String runtimeVersion = Names.VERSION;
/**
* Set of contributions that should be deployed to the runtime.
*
* @parameter
*/
public Dependency[] contributions = new Dependency[0];
/**
* Set of runtime extension artifacts that should be deployed to the runtime.
*
* @parameter
*/
public Dependency[] extensions = new Dependency[0];
/**
* Set of profiles for the runtime.
*
* @parameter
*/
public Dependency[] profiles = new Dependency[0];
/**
* Libraries available to application and runtime.
*
* @parameter
*/
public Dependency[] shared;
/**
* Allows the optional in-line specification of system configuration in the plugin configuration.
*
* @parameter
*/
public String systemConfig;
/**
* Build output directory.
*
* @parameter expression="${project.build.directory}"
* @required
*/
public File outputDirectory;
/**
* Allows the optional in-line specification of an expected error
*
* @parameter
*/
public String errorText;
/**
* JDK and system classpath packages to hide from the runtime classpath.
*
* @parameter
*/
public String[] hiddenPackages = MavenHiddenPackages.getPackages();
/**
* @component
*/
public RepositorySystem repositorySystem;
/**
* The current repository/network configuration of Maven.
*
* @parameter default-value="${repositorySystemSession}"
* @readonly
*/
public RepositorySystemSession session;
/**
* The project's remote repositories to use for the resolution of project dependencies.
*
* @parameter default-value="${project.remoteProjectRepositories}"
* @readonly
*/
private List projectRepositories;
public void execute() throws MojoExecutionException, MojoFailureException {
if (skip || Boolean.parseBoolean(System.getProperty("maven.test.skip"))) {
getLog().info("Skipping integration tests by user request.");
return;
}
Resolver resolver = new Resolver(repositorySystem, session, projectRepositories, runtimeVersion);
PluginBootConfiguration configuration = createBootConfiguration(resolver);
Thread.currentThread().setContextClassLoader(configuration.getBootClassLoader());
MavenRuntimeBooter booter = new MavenRuntimeBooter(configuration);
try {
PluginRuntime runtime = booter.boot();
// load the contributions
deployContributions(runtime, resolver);
MavenDeployer deployer = new MavenDeployer(compositeNamespace, compositeName, buildDirectory, getLog());
boolean continueDeployment = deployer.deploy(runtime, errorText);
if (!continueDeployment) {
return;
}
TestRunner runner = new TestRunner(reportsDirectory, trimStackTrace, getLog(), ignoreTestFailures);
runner.executeTests(runtime);
tryLatch(runtime);
} catch (RuntimeException e) {
// log unexpected errors since Maven sometimes swallows them
getLog().error(e);
throw e;
} catch (Fabric3PluginException | InitializationException e) {
throw new MojoExecutionException(e.getMessage(), e);
} finally {
try {
booter.shutdown();
} catch (Exception e) {
// ignore
}
}
}
/**
* Waits on a latch component if one is configured for the test run.
*
* @param runtime the runtime
*/
private void tryLatch(PluginRuntime runtime) {
Object latchComponent = runtime.getComponent(Object.class, PluginConstants.TEST_LATCH_SERVICE);
if (latchComponent != null) {
Class> type = latchComponent.getClass();
try {
Method method = type.getDeclaredMethod("await");
getLog().info("Waiting on Fabric3 runtime latch");
method.invoke(latchComponent);
getLog().info("Fabric3 runtime latch released");
} catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException | SecurityException | NoSuchMethodException e) {
getLog().error("Exception attempting to wait on latch service", e);
}
}
}
/**
* Resolves and deploys configured contributions.
*
* @param runtime the runtime
* @throws MojoExecutionException if a deployment error occurs
*/
private void deployContributions(PluginRuntime runtime, Resolver resolver) throws MojoExecutionException {
if (contributions.length <= 0) {
return;
}
try {
ContributionService contributionService = runtime.getComponent(ContributionService.class, Names.CONTRIBUTION_SERVICE_URI);
Domain domain = runtime.getComponent(Domain.class, Names.APPLICATION_DOMAIN_URI);
List sources = new ArrayList<>();
Set artifacts = convert(contributions);
Set resolvedArtifacts = resolver.resolve(artifacts);
for (URL url : resolvedArtifacts) {
URI uri = URI.create(new File(url.getFile()).getName());
ContributionSource source = new FileContributionSource(uri, url, -1, true);
sources.add(source);
}
List uris = contributionService.store(sources);
contributionService.install(uris);
domain.include(uris);
} catch (ArtifactResolutionException | InstallException | ContributionNotFoundException | DeploymentException | StoreException e) {
throw new MojoExecutionException("Error installing contributions", e);
}
}
/**
* Recursively cleans the F3 temporary directory.
*/
private static void clearTempFiles() {
File f3TempDir = new File(System.getProperty("java.io.tmpdir"), ".f3");
try {
FileHelper.deleteDirectory(f3TempDir);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Creates the configuration to boot the Maven runtime, including resolving dependencies.
*
* @return the boot configuration
* @throws MojoExecutionException if there is an error creating the configuration
*/
private PluginBootConfiguration createBootConfiguration(Resolver resolver) throws MojoExecutionException {
try {
Set runtimeArtifacts = resolver.resolveRuntimeArtifacts();
Set sharedArtifacts = convert(shared);
Set hostArtifacts = resolver.resolveHostArtifacts(sharedArtifacts);
Set extensionArtifacts = convert(extensions);
extensionArtifacts.add(new DefaultArtifact(FABRIC3_GROUP_ID, "fabric3-maven-extension", "jar", runtimeVersion));
Set profileArtifacts = convert(profiles);
List runtimeExtensions = resolver.resolveRuntimeExtensions(extensionArtifacts, profileArtifacts);
Set moduleDependencies = resolveModuleDependencies(hostArtifacts, resolver);
ClassLoader parentClassLoader = createParentClassLoader();
ClassLoader hostClassLoader = ClassLoaderHelper.createHostClassLoader(parentClassLoader, hostArtifacts);
ClassLoader bootClassLoader = ClassLoaderHelper.createBootClassLoader(hostClassLoader, runtimeArtifacts);
PluginBootConfiguration configuration = new PluginBootConfiguration();
configuration.setBootClassLoader(bootClassLoader);
configuration.setHostClassLoader(hostClassLoader);
MavenDestinationRouter router = new MavenDestinationRouter(getLog());
configuration.setRouter(router);
configuration.setExtensions(runtimeExtensions);
configuration.setModuleDependencies(moduleDependencies);
configuration.setOutputDirectory(outputDirectory);
configuration.setSystemConfig(systemConfig);
return configuration;
} catch (DependencyResolutionException | ArtifactResolutionException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}
private ClassLoader createParentClassLoader() {
ClassLoader parentClassLoader = getClass().getClassLoader();
if (hiddenPackages.length > 0) {
// mask hidden JDK and system classpath packages
parentClassLoader = new MaskingClassLoader(parentClassLoader, hiddenPackages);
}
return parentClassLoader;
}
private Set convert(Dependency[] dependencies) {
if (dependencies == null) {
return Collections.emptySet();
}
Set artifacts = new HashSet<>(dependencies.length);
for (Dependency dependency : dependencies) {
Artifact artifact = convert(dependency);
artifacts.add(artifact);
}
return artifacts;
}
private Artifact convert(Dependency dependency) {
String groupId = dependency.getGroupId();
String artifactId = dependency.getArtifactId();
String classifier = dependency.getClassifier();
String type = dependency.getType();
String version = dependency.getVersion();
return new DefaultArtifact(groupId, artifactId, classifier, type, version);
}
/**
* Calculates module dependencies based on the set of project artifacts. Module dependencies must be visible to implementation code in a composite and
* encompass project artifacts minus artifacts provided by the host classloader and those that are "provided scope".
*
* @param hostArtifacts the set of host artifacts
* @return the set of URLs pointing to module dependencies.
*/
public Set resolveModuleDependencies(Set hostArtifacts, Resolver resolver) throws MojoExecutionException {
try {
Set projectDependencies = calculateProjectDependencies(resolver);
Set urls = new LinkedHashSet<>();
for (org.eclipse.aether.graph.Dependency dependency : projectDependencies) {
String scope = dependency.getScope();
Artifact artifact = dependency.getArtifact();
if (hostArtifacts.contains(artifact) || "provided".equals(scope)) {
continue;
}
File pathElement = artifact.getFile();
URL url = pathElement.toURI().toURL();
urls.add(url);
}
return urls;
} catch (MalformedURLException | DependencyResolutionException e) {
// toURI should have encoded the URL
throw new MojoExecutionException(e.getMessage(), e);
}
}
private Set calculateProjectDependencies(Resolver resolver) throws DependencyResolutionException {
// add all declared project dependencies
Set artifacts = new HashSet<>();
for (Dependency dependency : project.getDependencies()) {
Set resolved = resolver.resolveTransitively(convert(dependency));
for (Artifact artifact : resolved) {
artifacts.add(new org.eclipse.aether.graph.Dependency(artifact, dependency.getScope()));
}
}
// include any artifacts that have been added by other plugins (e.g. Clover see FABRICTHREE-220)
for (org.apache.maven.artifact.Artifact dependency : project.getDependencyArtifacts()) {
Set resolved = resolver.resolveTransitively(convertArtifact(dependency));
for (Artifact artifact : resolved) {
artifacts.add(new org.eclipse.aether.graph.Dependency(artifact, dependency.getScope()));
}
}
return artifacts;
}
private DefaultArtifact convertArtifact(org.apache.maven.artifact.Artifact artifact) {
String groupId = artifact.getGroupId();
String artifactId = artifact.getArtifactId();
String classifier = artifact.getClassifier();
String type = artifact.getType();
String version = artifact.getVersion();
DefaultArtifact converted = new DefaultArtifact(groupId, artifactId, classifier, type, version);
converted = (DefaultArtifact) converted.setFile(artifact.getFile()); // Aether creates a new instance so reassign it :-(
return converted;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy