/amps-maven-plugin/src/main/java/com/atlassian/maven/plugins/amps/RemoteTestMojo.java
Java | 387 lines | 283 code | 64 blank | 40 comment | 37 complexity | dee3f602fac408f9700d1d6d7d67575d MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
- package com.atlassian.maven.plugins.amps;
- import aQute.bnd.osgi.Constants;
- import com.atlassian.maven.plugins.amps.util.ClassUtils;
- import com.atlassian.maven.plugins.amps.util.WiredTestInfo;
- import org.apache.commons.io.FileUtils;
- import org.apache.commons.lang3.StringUtils;
- import org.apache.http.auth.AuthScope;
- import org.apache.http.auth.UsernamePasswordCredentials;
- import org.apache.http.client.CredentialsProvider;
- import org.apache.http.client.methods.CloseableHttpResponse;
- import org.apache.http.client.methods.HttpGet;
- import org.apache.http.impl.client.BasicCredentialsProvider;
- import org.apache.http.impl.client.CloseableHttpClient;
- import org.apache.http.impl.client.HttpClients;
- import org.apache.maven.archiver.MavenArchiveConfiguration;
- import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
- import org.apache.maven.model.Build;
- import org.apache.maven.plugin.MojoExecutionException;
- import org.apache.maven.plugins.annotations.Component;
- import org.apache.maven.plugins.annotations.Execute;
- import org.apache.maven.plugins.annotations.LifecyclePhase;
- import org.apache.maven.plugins.annotations.Mojo;
- import org.apache.maven.plugins.annotations.Parameter;
- import org.apache.maven.plugins.annotations.ResolutionScope;
- import org.apache.maven.project.MavenProject;
- import org.codehaus.plexus.archiver.Archiver;
- import org.codehaus.plexus.archiver.jar.JarArchiver;
- import javax.ws.rs.core.UriBuilder;
- import java.io.File;
- import java.io.IOException;
- import java.net.URI;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.jar.JarFile;
- import java.util.jar.Manifest;
- import static com.atlassian.maven.plugins.amps.MavenGoals.getReportsDirectory;
- import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
- import static org.apache.commons.io.FileUtils.cleanDirectory;
- import static org.apache.commons.io.FileUtils.forceMkdir;
- import static org.apache.commons.lang3.StringUtils.isBlank;
- import static org.apache.commons.lang3.StringUtils.trim;
- import static org.apache.http.util.EntityUtils.consume;
- /**
- * If the current P2 plugin project contains "wired tests", this goal:
- * <ol>
- * <li>deploys the plugin</li>
- * <li>deploys the test plugin</li>
- * <li>runs {@code maven-failsafe-plugin:integration-test}</li>
- * <li>optionally runs {@code maven-failsafe-plugin:verify}</li>
- * </ol>
- */
- @Mojo(name = "remote-test", requiresDependencyResolution = ResolutionScope.TEST, defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST)
- @Execute(phase = LifecyclePhase.PACKAGE)
- public class RemoteTestMojo extends AbstractProductHandlerMojo {
- @Component
- private ArtifactHandlerManager artifactHandlerManager;
- /**
- * The archive configuration to use. See <a href="http://maven.apache.org/shared/maven-archiver/index.html">Maven
- * Archiver Reference</a>.
- */
- @Parameter
- private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
- /**
- * Pattern for to use to find integration tests. Only used if no test groups are defined.
- */
- @Parameter(property = "functional.test.pattern")
- private String functionalTestPattern = "it/**";
- /**
- * The directory containing generated test classes of the project being tested.
- */
- @Parameter(property = "project.build.testOutputDirectory", required = true)
- private File testClassesDirectory;
- @Parameter(property = "maven.test.skip", defaultValue = "false")
- private boolean testsSkip;
- @Parameter(property = "skipTests", defaultValue = "false")
- private boolean skipTests;
- /**
- * Skip the integration tests along with any product startups
- */
- @Parameter(property = "skipITs", defaultValue = "false")
- private boolean skipITs;
- /**
- * HTTP port for the servlet containers
- */
- @Parameter(property = "http.port", defaultValue = "80")
- protected int httpPort;
- /**
- * Username of user that will install the plugin
- */
- @Parameter(property = "pdk.username", defaultValue = "admin")
- protected String pdkUsername;
- /**
- * Password of user that will install the plugin
- */
- @Parameter(property = "pdk.password", defaultValue = "admin")
- protected String pdkPassword;
- @Parameter
- protected List<ProductArtifact> deployArtifacts = new ArrayList<>();
- /**
- * Denotes test category as defined by surefire/failsafe notion of groups. In JUnit4, this affects tests annotated
- * with {@link org.junit.experimental.categories.Category Category} annotation.
- */
- @Parameter
- protected String category;
- protected void doExecute() throws MojoExecutionException {
- if (isBlank(server)) {
- getLog().error("server is not set!");
- return;
- }
- if (contextPath == null || trim(contextPath).equals("/")) {
- contextPath = "";
- }
- if (httpPort < 1) {
- httpPort = 80;
- }
- if (!shouldBuildTestPlugin()) {
- getLog().info("shouldBuildTestPlugin is false... skipping test run!");
- return;
- }
- final MavenProject project = getMavenContext().getProject();
- // workaround for MNG-1682/MNG-2426: force maven to install artifact using the "jar" handler
- project.getArtifact().setArtifactHandler(artifactHandlerManager.getArtifactHandler("jar"));
- if (!new File(testClassesDirectory, "it").exists()) {
- getLog().info("No integration tests found");
- return;
- }
- if (skipTests || testsSkip || skipITs) {
- getLog().info("Integration tests skipped");
- return;
- }
- final MavenGoals goals = getMavenGoals();
- final String pluginJar = targetDirectory.getAbsolutePath() + "/" + finalName + ".jar";
- runTests(goals, pluginJar, copy(systemPropertyVariables));
- }
- private Map<String, Object> copy(Map<String, Object> systemPropertyVariables) {
- return new HashMap<>(systemPropertyVariables);
- }
- private String getBaseUrl(String server, final int actualHttpPort, String contextPath) {
- String port = actualHttpPort != 80 ? ":" + actualHttpPort : "";
- server = server.startsWith("http") ? server : "http://" + server;
- if (!contextPath.startsWith("/") && StringUtils.isNotBlank(contextPath)) {
- contextPath = "/" + contextPath;
- }
- return server + port + contextPath;
- }
- private void runTests(final MavenGoals goals, final String pluginJar, final Map<String, Object> systemProperties)
- throws MojoExecutionException {
- try {
- MavenContext ctx = getMavenContext();
- Build build = ctx.getProject().getBuild();
- File buildDir = new File(build.getDirectory());
- File testClassesDir = new File(build.getTestOutputDirectory());
- List<String> wiredTestClasses = getWiredTestClassnames(testClassesDir);
- if (wiredTestClasses.isEmpty()) {
- getLog().info("No wired integration tests found, skipping remote testing...");
- return;
- }
- List<String> includes = new ArrayList<>(wiredTestClasses.size());
- for (String wiredClass : wiredTestClasses) {
- String includePath = wiredClass.replaceAll("\\.", "/");
- includes.add(includePath + "*");
- }
- List<String> excludes = Collections.emptyList();
- systemProperties.put("http.port", httpPort);
- systemProperties.put("context.path", contextPath);
- systemProperties.put("plugin.jar", pluginJar);
- // yes, this means you only get one base url if multiple products, but that is what selenium would expect
- if (!systemProperties.containsKey("baseurl")) {
- systemProperties.put("baseurl", getBaseUrl(server, httpPort, contextPath));
- }
- Map<ProductArtifact, File> frameworkFiles = getFrameworkFiles();
- File junitFile = null;
- //we MUST install junit first!
- for (Map.Entry<ProductArtifact, File> entry : frameworkFiles.entrySet()) {
- ProductArtifact artifact = entry.getKey();
- File artifactFile = entry.getValue();
- if (artifactFile.getName().startsWith("org.apache.servicemix.bundles.junit")) {
- junitFile = artifactFile;
- frameworkFiles.remove(artifact);
- break;
- }
- }
- File mainPlugin = new File(buildDir, finalName + ".jar");
- File testPlugin = new File(buildDir, finalName + "-tests.jar");
- if (junitFile == null || !junitFile.exists()) {
- throw new MojoExecutionException("couldn't find junit!!!!");
- }
- installPluginFileIfNotInstalled(junitFile);
- for (Map.Entry<ProductArtifact, File> pluginEntry : frameworkFiles.entrySet()) {
- installPluginFileIfNotInstalled(pluginEntry.getValue());
- }
- installPluginFile(mainPlugin);
- installPluginFile(testPlugin);
- // Actually run the tests
- final String reportsDirectory =
- getReportsDirectory(targetDirectory, "group-" + NO_TEST_GROUP, "remote");
- goals.runIntegrationTests(reportsDirectory, includes, excludes, systemProperties, category, null);
- goals.runVerify(reportsDirectory);
- } catch (Exception e) {
- throw new MojoExecutionException("Error running remote tests...", e);
- }
- }
- private void installPluginFileIfNotInstalled(final File pluginFile) throws IOException, MojoExecutionException {
- getLog().info("checking to see if we need to install " + pluginFile.getName());
- final Manifest manifest = getManifest(pluginFile);
- String pluginKey = null;
- String pluginVersion = null;
- if (manifest == null) {
- getLog().info("no manifest found for plugin!");
- } else {
- pluginKey = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
- pluginVersion = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
- getLog().info("pluginKey from manifest is: " + pluginKey);
- }
- if (isBlank(pluginKey)) {
- getLog().info("no plugin key found, installing without check...");
- installPluginFile(pluginFile);
- } else {
- boolean foundPlugin = false;
- if (pluginExists(pluginKey + "-key")) {
- getLog().info("found the plugin!");
- foundPlugin = true;
- } else {
- getLog().info("not found, trying again with version tacked on ...");
- if (pluginExists(pluginKey + "-" + pluginVersion + "-key")) {
- getLog().info("found the plugin!");
- foundPlugin = true;
- }
- }
- if (foundPlugin) {
- getLog().debug("found the plugin ...");
- // TODO: check version and remove/install if we have an update
- } else {
- getLog().info("didn't find the plugin, so I'm installing it ...");
- installPluginFile(pluginFile);
- }
- }
- }
- private boolean pluginExists(final String pluginPath) throws IOException {
- final String relativePluginUrl = contextPath + "/rest/plugins/1.0/" + pluginPath;
- getLog().info("looking up plugin from: " + relativePluginUrl);
- final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
- credentialsProvider.setCredentials(
- new AuthScope(server, httpPort),
- new UsernamePasswordCredentials(pdkUsername, pdkPassword));
- final URI pluginUri = UriBuilder.fromPath(relativePluginUrl)
- .scheme("http")
- .host(server)
- .port(httpPort)
- .build();
- final HttpGet httpGet = new HttpGet(pluginUri);
- try (final CloseableHttpClient httpClient = HttpClients.custom()
- .setDefaultCredentialsProvider(credentialsProvider)
- .build();
- final CloseableHttpResponse response = httpClient.execute(httpGet)) {
- final int statusCode = response.getStatusLine().getStatusCode();
- consume(response.getEntity());
- return statusCode != HTTP_NOT_FOUND;
- }
- }
- private static Manifest getManifest(final File jarFile) throws IOException {
- try (final JarFile jar = new JarFile(jarFile)) {
- return jar.getManifest();
- }
- }
- private void installPluginFile(File pluginFile) throws MojoExecutionException {
- getLog().info("trying to install plugin with the following properties:");
- getLog().info("pluginFile: " + pluginFile.getAbsolutePath());
- getLog().info("pluginKey: " + pluginFile.getName());
- getLog().info("server: " + server);
- getLog().info("httpPort: " + httpPort);
- getLog().info("contextPath: " + contextPath);
- getLog().info("username: " + pdkUsername);
- getMavenGoals().installPlugin(new PdkParams.Builder()
- .pluginFile(pluginFile.getAbsolutePath())
- .pluginKey(pluginFile.getName())
- .server(server)
- .port(httpPort)
- .contextPath(contextPath)
- .username(pdkUsername)
- .password(pdkPassword)
- .build());
- }
- private List<String> getWiredTestClassnames(File testClassesDir) {
- MavenProject prj = getMavenContext().getProject();
- List<String> wiredClasses = new ArrayList<>();
- if (testClassesDir.exists()) {
- Collection<File> classFiles = FileUtils.listFiles(testClassesDir, new String[]{"class"}, true);
- for (File classFile : classFiles) {
- String className = ClassUtils.getClassnameFromFile(classFile, prj.getBuild().getTestOutputDirectory());
- WiredTestInfo wiredInfo = ClassUtils.getWiredTestInfo(classFile);
- if (wiredInfo.isWiredTest()) {
- wiredClasses.add(className);
- }
- }
- }
- return wiredClasses;
- }
- private Map<ProductArtifact, File> getFrameworkFiles() throws MojoExecutionException {
- final List<ProductArtifact> pluginsToDeploy = new ArrayList<>(getTestFrameworkPlugins());
- pluginsToDeploy.addAll(deployArtifacts);
- final Map<ProductArtifact, File> artifactFileMap = new HashMap<>(pluginsToDeploy.size());
- try {
- final File tmpDir = new File(getMavenContext().getProject().getBuild().getDirectory(), "tmp-artifacts");
- forceMkdir(tmpDir);
- cleanDirectory(tmpDir);
- getMavenGoals().copyPlugins(tmpDir, pluginsToDeploy);
- for (final File artifactFile : FileUtils.listFiles(tmpDir, null, false)) {
- pluginsToDeploy.stream()
- .filter(productArtifact -> artifactFile.getName().startsWith(productArtifact.getArtifactId()))
- .findFirst()
- .ifPresent(productArtifact -> artifactFileMap.put(productArtifact, artifactFile));
- }
- return artifactFileMap;
- } catch (Exception e) {
- throw new MojoExecutionException("Error copying framework files", e);
- }
- }
- }