PageRenderTime 39ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/amps-maven-plugin/src/main/java/com/atlassian/maven/plugins/amps/RemoteTestMojo.java

https://bitbucket.org/atlassian/amps
Java | 387 lines | 283 code | 64 blank | 40 comment | 37 complexity | dee3f602fac408f9700d1d6d7d67575d MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
  1. package com.atlassian.maven.plugins.amps;
  2. import aQute.bnd.osgi.Constants;
  3. import com.atlassian.maven.plugins.amps.util.ClassUtils;
  4. import com.atlassian.maven.plugins.amps.util.WiredTestInfo;
  5. import org.apache.commons.io.FileUtils;
  6. import org.apache.commons.lang3.StringUtils;
  7. import org.apache.http.auth.AuthScope;
  8. import org.apache.http.auth.UsernamePasswordCredentials;
  9. import org.apache.http.client.CredentialsProvider;
  10. import org.apache.http.client.methods.CloseableHttpResponse;
  11. import org.apache.http.client.methods.HttpGet;
  12. import org.apache.http.impl.client.BasicCredentialsProvider;
  13. import org.apache.http.impl.client.CloseableHttpClient;
  14. import org.apache.http.impl.client.HttpClients;
  15. import org.apache.maven.archiver.MavenArchiveConfiguration;
  16. import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
  17. import org.apache.maven.model.Build;
  18. import org.apache.maven.plugin.MojoExecutionException;
  19. import org.apache.maven.plugins.annotations.Component;
  20. import org.apache.maven.plugins.annotations.Execute;
  21. import org.apache.maven.plugins.annotations.LifecyclePhase;
  22. import org.apache.maven.plugins.annotations.Mojo;
  23. import org.apache.maven.plugins.annotations.Parameter;
  24. import org.apache.maven.plugins.annotations.ResolutionScope;
  25. import org.apache.maven.project.MavenProject;
  26. import org.codehaus.plexus.archiver.Archiver;
  27. import org.codehaus.plexus.archiver.jar.JarArchiver;
  28. import javax.ws.rs.core.UriBuilder;
  29. import java.io.File;
  30. import java.io.IOException;
  31. import java.net.URI;
  32. import java.util.ArrayList;
  33. import java.util.Collection;
  34. import java.util.Collections;
  35. import java.util.HashMap;
  36. import java.util.List;
  37. import java.util.Map;
  38. import java.util.jar.JarFile;
  39. import java.util.jar.Manifest;
  40. import static com.atlassian.maven.plugins.amps.MavenGoals.getReportsDirectory;
  41. import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
  42. import static org.apache.commons.io.FileUtils.cleanDirectory;
  43. import static org.apache.commons.io.FileUtils.forceMkdir;
  44. import static org.apache.commons.lang3.StringUtils.isBlank;
  45. import static org.apache.commons.lang3.StringUtils.trim;
  46. import static org.apache.http.util.EntityUtils.consume;
  47. /**
  48. * If the current P2 plugin project contains "wired tests", this goal:
  49. * <ol>
  50. * <li>deploys the plugin</li>
  51. * <li>deploys the test plugin</li>
  52. * <li>runs {@code maven-failsafe-plugin:integration-test}</li>
  53. * <li>optionally runs {@code maven-failsafe-plugin:verify}</li>
  54. * </ol>
  55. */
  56. @Mojo(name = "remote-test", requiresDependencyResolution = ResolutionScope.TEST, defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST)
  57. @Execute(phase = LifecyclePhase.PACKAGE)
  58. public class RemoteTestMojo extends AbstractProductHandlerMojo {
  59. @Component
  60. private ArtifactHandlerManager artifactHandlerManager;
  61. /**
  62. * The archive configuration to use. See <a href="http://maven.apache.org/shared/maven-archiver/index.html">Maven
  63. * Archiver Reference</a>.
  64. */
  65. @Parameter
  66. private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
  67. /**
  68. * Pattern for to use to find integration tests. Only used if no test groups are defined.
  69. */
  70. @Parameter(property = "functional.test.pattern")
  71. private String functionalTestPattern = "it/**";
  72. /**
  73. * The directory containing generated test classes of the project being tested.
  74. */
  75. @Parameter(property = "project.build.testOutputDirectory", required = true)
  76. private File testClassesDirectory;
  77. @Parameter(property = "maven.test.skip", defaultValue = "false")
  78. private boolean testsSkip;
  79. @Parameter(property = "skipTests", defaultValue = "false")
  80. private boolean skipTests;
  81. /**
  82. * Skip the integration tests along with any product startups
  83. */
  84. @Parameter(property = "skipITs", defaultValue = "false")
  85. private boolean skipITs;
  86. /**
  87. * HTTP port for the servlet containers
  88. */
  89. @Parameter(property = "http.port", defaultValue = "80")
  90. protected int httpPort;
  91. /**
  92. * Username of user that will install the plugin
  93. */
  94. @Parameter(property = "pdk.username", defaultValue = "admin")
  95. protected String pdkUsername;
  96. /**
  97. * Password of user that will install the plugin
  98. */
  99. @Parameter(property = "pdk.password", defaultValue = "admin")
  100. protected String pdkPassword;
  101. @Parameter
  102. protected List<ProductArtifact> deployArtifacts = new ArrayList<>();
  103. /**
  104. * Denotes test category as defined by surefire/failsafe notion of groups. In JUnit4, this affects tests annotated
  105. * with {@link org.junit.experimental.categories.Category Category} annotation.
  106. */
  107. @Parameter
  108. protected String category;
  109. protected void doExecute() throws MojoExecutionException {
  110. if (isBlank(server)) {
  111. getLog().error("server is not set!");
  112. return;
  113. }
  114. if (contextPath == null || trim(contextPath).equals("/")) {
  115. contextPath = "";
  116. }
  117. if (httpPort < 1) {
  118. httpPort = 80;
  119. }
  120. if (!shouldBuildTestPlugin()) {
  121. getLog().info("shouldBuildTestPlugin is false... skipping test run!");
  122. return;
  123. }
  124. final MavenProject project = getMavenContext().getProject();
  125. // workaround for MNG-1682/MNG-2426: force maven to install artifact using the "jar" handler
  126. project.getArtifact().setArtifactHandler(artifactHandlerManager.getArtifactHandler("jar"));
  127. if (!new File(testClassesDirectory, "it").exists()) {
  128. getLog().info("No integration tests found");
  129. return;
  130. }
  131. if (skipTests || testsSkip || skipITs) {
  132. getLog().info("Integration tests skipped");
  133. return;
  134. }
  135. final MavenGoals goals = getMavenGoals();
  136. final String pluginJar = targetDirectory.getAbsolutePath() + "/" + finalName + ".jar";
  137. runTests(goals, pluginJar, copy(systemPropertyVariables));
  138. }
  139. private Map<String, Object> copy(Map<String, Object> systemPropertyVariables) {
  140. return new HashMap<>(systemPropertyVariables);
  141. }
  142. private String getBaseUrl(String server, final int actualHttpPort, String contextPath) {
  143. String port = actualHttpPort != 80 ? ":" + actualHttpPort : "";
  144. server = server.startsWith("http") ? server : "http://" + server;
  145. if (!contextPath.startsWith("/") && StringUtils.isNotBlank(contextPath)) {
  146. contextPath = "/" + contextPath;
  147. }
  148. return server + port + contextPath;
  149. }
  150. private void runTests(final MavenGoals goals, final String pluginJar, final Map<String, Object> systemProperties)
  151. throws MojoExecutionException {
  152. try {
  153. MavenContext ctx = getMavenContext();
  154. Build build = ctx.getProject().getBuild();
  155. File buildDir = new File(build.getDirectory());
  156. File testClassesDir = new File(build.getTestOutputDirectory());
  157. List<String> wiredTestClasses = getWiredTestClassnames(testClassesDir);
  158. if (wiredTestClasses.isEmpty()) {
  159. getLog().info("No wired integration tests found, skipping remote testing...");
  160. return;
  161. }
  162. List<String> includes = new ArrayList<>(wiredTestClasses.size());
  163. for (String wiredClass : wiredTestClasses) {
  164. String includePath = wiredClass.replaceAll("\\.", "/");
  165. includes.add(includePath + "*");
  166. }
  167. List<String> excludes = Collections.emptyList();
  168. systemProperties.put("http.port", httpPort);
  169. systemProperties.put("context.path", contextPath);
  170. systemProperties.put("plugin.jar", pluginJar);
  171. // yes, this means you only get one base url if multiple products, but that is what selenium would expect
  172. if (!systemProperties.containsKey("baseurl")) {
  173. systemProperties.put("baseurl", getBaseUrl(server, httpPort, contextPath));
  174. }
  175. Map<ProductArtifact, File> frameworkFiles = getFrameworkFiles();
  176. File junitFile = null;
  177. //we MUST install junit first!
  178. for (Map.Entry<ProductArtifact, File> entry : frameworkFiles.entrySet()) {
  179. ProductArtifact artifact = entry.getKey();
  180. File artifactFile = entry.getValue();
  181. if (artifactFile.getName().startsWith("org.apache.servicemix.bundles.junit")) {
  182. junitFile = artifactFile;
  183. frameworkFiles.remove(artifact);
  184. break;
  185. }
  186. }
  187. File mainPlugin = new File(buildDir, finalName + ".jar");
  188. File testPlugin = new File(buildDir, finalName + "-tests.jar");
  189. if (junitFile == null || !junitFile.exists()) {
  190. throw new MojoExecutionException("couldn't find junit!!!!");
  191. }
  192. installPluginFileIfNotInstalled(junitFile);
  193. for (Map.Entry<ProductArtifact, File> pluginEntry : frameworkFiles.entrySet()) {
  194. installPluginFileIfNotInstalled(pluginEntry.getValue());
  195. }
  196. installPluginFile(mainPlugin);
  197. installPluginFile(testPlugin);
  198. // Actually run the tests
  199. final String reportsDirectory =
  200. getReportsDirectory(targetDirectory, "group-" + NO_TEST_GROUP, "remote");
  201. goals.runIntegrationTests(reportsDirectory, includes, excludes, systemProperties, category, null);
  202. goals.runVerify(reportsDirectory);
  203. } catch (Exception e) {
  204. throw new MojoExecutionException("Error running remote tests...", e);
  205. }
  206. }
  207. private void installPluginFileIfNotInstalled(final File pluginFile) throws IOException, MojoExecutionException {
  208. getLog().info("checking to see if we need to install " + pluginFile.getName());
  209. final Manifest manifest = getManifest(pluginFile);
  210. String pluginKey = null;
  211. String pluginVersion = null;
  212. if (manifest == null) {
  213. getLog().info("no manifest found for plugin!");
  214. } else {
  215. pluginKey = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
  216. pluginVersion = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
  217. getLog().info("pluginKey from manifest is: " + pluginKey);
  218. }
  219. if (isBlank(pluginKey)) {
  220. getLog().info("no plugin key found, installing without check...");
  221. installPluginFile(pluginFile);
  222. } else {
  223. boolean foundPlugin = false;
  224. if (pluginExists(pluginKey + "-key")) {
  225. getLog().info("found the plugin!");
  226. foundPlugin = true;
  227. } else {
  228. getLog().info("not found, trying again with version tacked on ...");
  229. if (pluginExists(pluginKey + "-" + pluginVersion + "-key")) {
  230. getLog().info("found the plugin!");
  231. foundPlugin = true;
  232. }
  233. }
  234. if (foundPlugin) {
  235. getLog().debug("found the plugin ...");
  236. // TODO: check version and remove/install if we have an update
  237. } else {
  238. getLog().info("didn't find the plugin, so I'm installing it ...");
  239. installPluginFile(pluginFile);
  240. }
  241. }
  242. }
  243. private boolean pluginExists(final String pluginPath) throws IOException {
  244. final String relativePluginUrl = contextPath + "/rest/plugins/1.0/" + pluginPath;
  245. getLog().info("looking up plugin from: " + relativePluginUrl);
  246. final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
  247. credentialsProvider.setCredentials(
  248. new AuthScope(server, httpPort),
  249. new UsernamePasswordCredentials(pdkUsername, pdkPassword));
  250. final URI pluginUri = UriBuilder.fromPath(relativePluginUrl)
  251. .scheme("http")
  252. .host(server)
  253. .port(httpPort)
  254. .build();
  255. final HttpGet httpGet = new HttpGet(pluginUri);
  256. try (final CloseableHttpClient httpClient = HttpClients.custom()
  257. .setDefaultCredentialsProvider(credentialsProvider)
  258. .build();
  259. final CloseableHttpResponse response = httpClient.execute(httpGet)) {
  260. final int statusCode = response.getStatusLine().getStatusCode();
  261. consume(response.getEntity());
  262. return statusCode != HTTP_NOT_FOUND;
  263. }
  264. }
  265. private static Manifest getManifest(final File jarFile) throws IOException {
  266. try (final JarFile jar = new JarFile(jarFile)) {
  267. return jar.getManifest();
  268. }
  269. }
  270. private void installPluginFile(File pluginFile) throws MojoExecutionException {
  271. getLog().info("trying to install plugin with the following properties:");
  272. getLog().info("pluginFile: " + pluginFile.getAbsolutePath());
  273. getLog().info("pluginKey: " + pluginFile.getName());
  274. getLog().info("server: " + server);
  275. getLog().info("httpPort: " + httpPort);
  276. getLog().info("contextPath: " + contextPath);
  277. getLog().info("username: " + pdkUsername);
  278. getMavenGoals().installPlugin(new PdkParams.Builder()
  279. .pluginFile(pluginFile.getAbsolutePath())
  280. .pluginKey(pluginFile.getName())
  281. .server(server)
  282. .port(httpPort)
  283. .contextPath(contextPath)
  284. .username(pdkUsername)
  285. .password(pdkPassword)
  286. .build());
  287. }
  288. private List<String> getWiredTestClassnames(File testClassesDir) {
  289. MavenProject prj = getMavenContext().getProject();
  290. List<String> wiredClasses = new ArrayList<>();
  291. if (testClassesDir.exists()) {
  292. Collection<File> classFiles = FileUtils.listFiles(testClassesDir, new String[]{"class"}, true);
  293. for (File classFile : classFiles) {
  294. String className = ClassUtils.getClassnameFromFile(classFile, prj.getBuild().getTestOutputDirectory());
  295. WiredTestInfo wiredInfo = ClassUtils.getWiredTestInfo(classFile);
  296. if (wiredInfo.isWiredTest()) {
  297. wiredClasses.add(className);
  298. }
  299. }
  300. }
  301. return wiredClasses;
  302. }
  303. private Map<ProductArtifact, File> getFrameworkFiles() throws MojoExecutionException {
  304. final List<ProductArtifact> pluginsToDeploy = new ArrayList<>(getTestFrameworkPlugins());
  305. pluginsToDeploy.addAll(deployArtifacts);
  306. final Map<ProductArtifact, File> artifactFileMap = new HashMap<>(pluginsToDeploy.size());
  307. try {
  308. final File tmpDir = new File(getMavenContext().getProject().getBuild().getDirectory(), "tmp-artifacts");
  309. forceMkdir(tmpDir);
  310. cleanDirectory(tmpDir);
  311. getMavenGoals().copyPlugins(tmpDir, pluginsToDeploy);
  312. for (final File artifactFile : FileUtils.listFiles(tmpDir, null, false)) {
  313. pluginsToDeploy.stream()
  314. .filter(productArtifact -> artifactFile.getName().startsWith(productArtifact.getArtifactId()))
  315. .findFirst()
  316. .ifPresent(productArtifact -> artifactFileMap.put(productArtifact, artifactFile));
  317. }
  318. return artifactFileMap;
  319. } catch (Exception e) {
  320. throw new MojoExecutionException("Error copying framework files", e);
  321. }
  322. }
  323. }