1 package com.atlassian.maven.plugins.amps;
2
3 import static com.google.common.collect.Iterables.transform;
4
5 import java.io.File;
6 import java.util.Collections;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Set;
12 import java.util.concurrent.Callable;
13 import java.util.concurrent.Executor;
14 import java.util.concurrent.ExecutorService;
15 import java.util.concurrent.Executors;
16
17 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
18 import org.apache.maven.plugin.MojoExecutionException;
19 import org.apache.maven.project.MavenProject;
20 import org.jfrog.maven.annomojo.annotations.MojoComponent;
21 import org.jfrog.maven.annomojo.annotations.MojoGoal;
22 import org.jfrog.maven.annomojo.annotations.MojoParameter;
23 import org.jfrog.maven.annomojo.annotations.MojoRequiresDependencyResolution;
24
25 import com.atlassian.maven.plugins.amps.product.ProductHandler;
26 import com.atlassian.util.concurrent.AsyncCompleter;
27 import com.atlassian.util.concurrent.ExceptionPolicy;
28 import com.google.common.base.Function;
29
30
31
32
33 @MojoGoal("integration-test")
34 @MojoRequiresDependencyResolution("test")
35 public class IntegrationTestMojo extends AbstractTestGroupsHandlerMojo
36 {
37
38
39
40 @MojoParameter(expression = "${functional.test.pattern}")
41 private String functionalTestPattern = "it/**";
42
43
44
45
46 @MojoParameter(expression = "${project.build.testOutputDirectory}", required = true)
47 private File testClassesDirectory;
48
49
50
51
52
53 @MojoParameter(expression = "${testGroups}")
54 private String configuredTestGroupsToRun;
55
56
57
58
59 @MojoParameter(expression = "${no.webapp}", defaultValue = "false")
60 private boolean noWebapp = false;
61
62 @MojoComponent
63 private ArtifactHandlerManager artifactHandlerManager;
64
65 @MojoParameter(expression="${maven.test.skip}", defaultValue = "false")
66 private boolean testsSkip = false;
67
68 @MojoParameter(expression="${skipTests}", defaultValue = "false")
69 private boolean skipTests = false;
70
71
72
73
74 @MojoParameter(expression="${skipITs}", defaultValue = "false")
75 private boolean skipITs = false;
76
77 protected void doExecute() throws MojoExecutionException
78 {
79 final MavenProject project = getMavenContext().getProject();
80
81
82 project.getArtifact().setArtifactHandler(artifactHandlerManager.getArtifactHandler("jar"));
83
84 if (!new File(testClassesDirectory, "it").exists())
85 {
86 getLog().info("No integration tests found");
87 return;
88 }
89
90 if (skipTests || testsSkip || skipITs)
91 {
92 getLog().info("Integration tests skipped");
93 return;
94 }
95
96 final MavenGoals goals = getMavenGoals();
97 final String pluginJar = targetDirectory.getAbsolutePath() + "/" + finalName + ".jar";
98
99 final Set<String> configuredTestGroupIds = getTestGroupIds();
100 if (configuredTestGroupIds.isEmpty())
101 {
102 runTestsForTestGroup(NO_TEST_GROUP, goals, pluginJar, copy(systemPropertyVariables));
103 }
104 else if (configuredTestGroupsToRun != null)
105 {
106 String[] testGroupIdsToRun = configuredTestGroupsToRun.split(",");
107
108
109 for (String testGroupId : testGroupIdsToRun)
110 {
111 if (!configuredTestGroupIds.contains(testGroupId))
112 {
113 getLog().warn("Test group " + testGroupId + " does not exist");
114 }
115 else
116 {
117 runTestsForTestGroup(testGroupId, goals, pluginJar, copy(systemPropertyVariables));
118 }
119 }
120 }
121 else
122 {
123 for (String testGroupId : configuredTestGroupIds)
124 {
125 runTestsForTestGroup(testGroupId, goals, pluginJar, copy(systemPropertyVariables));
126 }
127 }
128 }
129
130 private Map<String,Object> copy(Map<String,Object> systemPropertyVariables)
131 {
132 return new HashMap<String,Object>(systemPropertyVariables);
133 }
134
135
136
137
138
139
140
141
142 protected Map<String, String> getProductFunctionalTestProperties(Product product)
143 {
144 return Collections.emptyMap();
145 }
146
147 private Set<String> getTestGroupIds() throws MojoExecutionException
148 {
149 Set<String> ids = new HashSet<String>();
150
151
152 for (TestGroup group : getTestGroups())
153 {
154 ids.add(group.getId());
155 }
156
157 return ids;
158 }
159
160 private void runTestsForTestGroup(String testGroupId, MavenGoals goals, String pluginJar, Map<String,Object> systemProperties) throws MojoExecutionException
161 {
162 List<String> includes = getIncludesForTestGroup(testGroupId);
163 List<String> excludes = getExcludesForTestGroup(testGroupId);
164
165 List<ProductExecution> productExecutions = getTestGroupProductExecutions(testGroupId);
166
167 ExecutorService executor = Executors.newFixedThreadPool(productExecutions.size());
168 AsyncCompleter completer = new AsyncCompleter.Builder(executor).handleExceptions(ExceptionPolicy.Policies.THROW).build();
169
170
171 for (Map<String, Object> productProperties : completer.invokeAll(transform(productExecutions, productStarter(pluginJar))))
172 {
173 systemProperties.putAll(productProperties);
174 }
175 if (productExecutions.size() == 1)
176 {
177 Product product = productExecutions.get(0).getProduct();
178 systemProperties.put("http.port", systemProperties.get("http." + product.getInstanceId() + ".port"));
179 systemProperties.put("context.path", product.getContextPath());
180 }
181 systemProperties.put("testGroup", testGroupId);
182 systemProperties.putAll(getTestGroupSystemProperties(testGroupId));
183
184
185 goals.runTests("group-" + testGroupId, containerId, includes, excludes, systemProperties, targetDirectory);
186
187
188 if (!noWebapp)
189 {
190 for (Void _ : completer.invokeAll(transform(productExecutions, productStopper()))) {}
191 }
192 executor.shutdown();
193 }
194
195 private Function<ProductExecution, Callable<Map<String, Object>>> productStarter(final String pluginJar)
196 {
197 return new Function<ProductExecution, Callable<Map<String,Object>>>()
198 {
199 @Override
200 public Callable<Map<String, Object>> apply(ProductExecution productExecution)
201 {
202 return new ProductStarter(pluginJar, productExecution);
203 }
204 };
205 }
206
207 private final class ProductStarter implements Callable<Map<String, Object>>
208 {
209 private final String pluginJar;
210 private final ProductExecution productExecution;
211
212 public ProductStarter(String pluginJar, ProductExecution productExecution)
213 {
214 this.pluginJar = pluginJar;
215 this.productExecution = productExecution;
216 }
217
218 @Override
219 public Map<String, Object> call() throws Exception
220 {
221 Map<String, Object> properties = new HashMap<String, Object>();
222 ProductHandler productHandler = productExecution.getProductHandler();
223 Product product = productExecution.getProduct();
224 product.setInstallPlugin(installPlugin);
225
226 int actualHttpPort = 0;
227 if (!noWebapp)
228 {
229 actualHttpPort = productHandler.start(product);
230 }
231
232 String baseUrl = MavenGoals.getBaseUrl(product.getServer(), actualHttpPort, product.getContextPath());
233
234 properties.put("http." + product.getInstanceId() + ".port", String.valueOf(actualHttpPort));
235 properties.put("context." + product.getInstanceId() + ".path", product.getContextPath());
236 properties.put("http." + product.getInstanceId() + ".url", MavenGoals.getBaseUrl(product.getServer(), actualHttpPort, product.getContextPath()));
237
238 properties.put("baseurl." + product.getInstanceId(), baseUrl);
239 properties.put("plugin.jar", pluginJar);
240
241 properties.put("baseurl", baseUrl);
242
243 properties.put("homedir." + product.getInstanceId(), productHandler.getHomeDirectory(product).getAbsolutePath());
244 if (!properties.containsKey("homedir"))
245 {
246 properties.put("homedir", productHandler.getHomeDirectory(product).getAbsolutePath());
247 }
248
249 properties.putAll(getProductFunctionalTestProperties(product));
250 return properties;
251 }
252 }
253
254 private Function<ProductExecution, Callable<Void>> productStopper()
255 {
256 return ProductStopper.INSTANCE;
257 }
258
259 enum ProductStopper implements Function<ProductExecution, Callable<Void>>
260 {
261 INSTANCE;
262
263 @Override
264 public Callable<Void> apply(final ProductExecution productExecution)
265 {
266 return new Callable<Void>()
267 {
268 @Override
269 public Void call() throws Exception
270 {
271 productExecution.getProductHandler().stop(productExecution.getProduct());
272 return null;
273 }
274 };
275 }
276 }
277
278 private Map<String, String> getTestGroupSystemProperties(String testGroupId)
279 {
280 if (NO_TEST_GROUP.equals(testGroupId))
281 {
282 return Collections.emptyMap();
283 }
284
285 for (TestGroup group : getTestGroups())
286 {
287 if (group.getId().equals(testGroupId))
288 {
289 return group.getSystemProperties();
290 }
291 }
292 return Collections.emptyMap();
293 }
294
295 private List<String> getIncludesForTestGroup(String testGroupId)
296 {
297 if (NO_TEST_GROUP.equals(testGroupId))
298 {
299 return Collections.singletonList(functionalTestPattern);
300 }
301 else
302 {
303 for (TestGroup group : getTestGroups())
304 {
305 if (group.getId().equals(testGroupId))
306 {
307 return group.getIncludes();
308 }
309 }
310 }
311 return Collections.singletonList(functionalTestPattern);
312 }
313
314
315 private List<String> getExcludesForTestGroup(String testGroupId)
316 {
317 if (NO_TEST_GROUP.equals(testGroupId))
318 {
319 return Collections.emptyList();
320 }
321 else
322 {
323 for (TestGroup group : getTestGroups())
324 {
325 if (group.getId().equals(testGroupId))
326 {
327 return group.getExcludes();
328 }
329 }
330 }
331 return Collections.emptyList();
332 }
333 }