1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.cloud.contract.maven.verifier;
18
19 import java.io.File;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.apache.maven.execution.MavenSession;
25 import org.apache.maven.model.Dependency;
26 import org.apache.maven.model.Resource;
27 import org.apache.maven.plugin.AbstractMojo;
28 import org.apache.maven.plugin.MojoExecution;
29 import org.apache.maven.plugin.MojoExecutionException;
30 import org.apache.maven.plugin.MojoFailureException;
31 import org.apache.maven.plugins.annotations.LifecyclePhase;
32 import org.apache.maven.plugins.annotations.Mojo;
33 import org.apache.maven.plugins.annotations.Parameter;
34 import org.apache.maven.plugins.annotations.ResolutionScope;
35 import org.apache.maven.project.MavenProject;
36 import org.eclipse.aether.RepositorySystemSession;
37
38 import org.springframework.cloud.contract.spec.ContractVerifierException;
39 import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
40 import org.springframework.cloud.contract.verifier.TestGenerator;
41 import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties;
42 import org.springframework.cloud.contract.verifier.config.TestFramework;
43 import org.springframework.cloud.contract.verifier.config.TestMode;
44 import org.springframework.util.StringUtils;
45
46
47
48
49
50
51
52 @Mojo(name = "generateTests", defaultPhase = LifecyclePhase.GENERATE_TEST_SOURCES,
53 requiresDependencyResolution = ResolutionScope.TEST)
54 public class GenerateTestsMojo extends AbstractMojo {
55
56 @Parameter(defaultValue = "${repositorySystemSession}", readonly = true)
57 private RepositorySystemSession repoSession;
58
59 @Parameter(property = "spring.cloud.contract.verifier.contractsDirectory",
60 defaultValue = "${project.basedir}/src/test/resources/contracts")
61 private File contractsDirectory;
62
63 @Parameter(defaultValue = "${project.build.directory}/generated-test-sources/contracts")
64 private File generatedTestSourcesDir;
65
66 @Parameter(defaultValue = "${project.build.directory}/generated-test-resources/contracts")
67 private File generatedTestResourcesDir;
68
69 @Parameter
70 private String basePackageForTests;
71
72 @Parameter
73 private String baseClassForTests;
74
75 @Parameter(defaultValue = "MOCKMVC")
76 private TestMode testMode;
77
78 @Parameter(defaultValue = "JUNIT5")
79 private TestFramework testFramework;
80
81 @Parameter
82 private String ruleClassForTests;
83
84 @Parameter
85 private String nameSuffixForTests;
86
87
88
89
90 @Parameter
91 private String[] imports;
92
93
94
95
96 @Parameter
97 private String[] staticImports;
98
99
100
101
102 @Parameter
103 private List<String> excludedFiles;
104
105
106
107
108 @Parameter(property = "includedFiles")
109 private List<String> includedFiles;
110
111
112
113
114
115 @Parameter(property = "spring.cloud.contract.verifier.assert.size", defaultValue = "false")
116 private boolean assertJsonSize;
117
118
119
120
121 @Parameter
122 private List<String> ignoredFiles;
123
124 @Parameter(defaultValue = "${project}", readonly = true)
125 private MavenProject project;
126
127 @Parameter(property = "spring.cloud.contract.verifier.skip", defaultValue = "false")
128 private boolean skip;
129
130 @Parameter(property = "maven.test.skip", defaultValue = "false")
131 private boolean mavenTestSkip;
132
133
134
135
136
137
138 @Parameter(property = "contractsRepositoryUrl")
139 private String contractsRepositoryUrl;
140
141 @Parameter(property = "contractDependency")
142 private Dependency contractDependency;
143
144
145
146
147
148
149
150 @Parameter(property = "contractsPath")
151 private String contractsPath;
152
153
154
155
156 @Parameter(property = "contractsMode", defaultValue = "CLASSPATH")
157 private StubRunnerProperties.StubsMode contractsMode;
158
159
160
161
162
163
164
165
166
167
168 @Parameter(property = "packageWithBaseClasses")
169 private String packageWithBaseClasses;
170
171
172
173
174
175
176
177
178
179 @Parameter(property = "baseClassMappings")
180 private List<BaseClassMapping> baseClassMappings;
181
182
183
184
185 @Parameter(property = "contractsRepositoryUsername")
186 private String contractsRepositoryUsername;
187
188
189
190
191 @Parameter(property = "contractsRepositoryPassword")
192 private String contractsRepositoryPassword;
193
194
195
196
197 @Parameter(property = "contractsRepositoryProxyHost")
198 private String contractsRepositoryProxyHost;
199
200
201
202
203 @Parameter(property = "contractsRepositoryProxyPort")
204 private Integer contractsRepositoryProxyPort;
205
206
207
208
209
210 @Parameter(property = "deleteStubsAfterTest", defaultValue = "true")
211 private boolean deleteStubsAfterTest;
212
213
214
215
216
217 @Parameter(property = "contractsProperties")
218 private Map<String, String> contractsProperties = new HashMap<>();
219
220
221
222
223
224 @Parameter(property = "failOnNoContracts", defaultValue = "true")
225 private boolean failOnNoContracts;
226
227
228
229
230
231
232
233 @Parameter(property = "failOnInProgress", defaultValue = "true")
234 private boolean failOnInProgress = true;
235
236
237
238
239
240 @Parameter(property = "incrementalContractTests", defaultValue = "true")
241 private boolean incrementalContractTests = true;
242
243 @Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true)
244 private MojoExecution mojoExecution;
245
246 @Parameter(defaultValue = "${session}", readonly = true, required = true)
247 private MavenSession session;
248
249 @Override
250 public void execute() throws MojoExecutionException, MojoFailureException {
251 if (this.skip || this.mavenTestSkip) {
252 if (this.skip) {
253 getLog().info("Skipping Spring Cloud Contract Verifier execution: spring.cloud.contract.verifier.skip="
254 + this.skip);
255 }
256 if (this.mavenTestSkip) {
257 getLog().info(
258 "Skipping Spring Cloud Contract Verifier execution: maven.test.skip=" + this.mavenTestSkip);
259 }
260 return;
261 }
262 getLog().info("Generating server tests source code for Spring Cloud Contract Verifier contract verification");
263 final ContractVerifierConfigProperties config = new ContractVerifierConfigProperties();
264 config.setFailOnInProgress(this.failOnInProgress);
265
266 File contractsDirectory = new MavenContractsDownloader(this.project, this.contractDependency,
267 this.contractsPath, this.contractsRepositoryUrl, this.contractsMode, getLog(),
268 this.contractsRepositoryUsername, this.contractsRepositoryPassword, this.contractsRepositoryProxyHost,
269 this.contractsRepositoryProxyPort, this.deleteStubsAfterTest, this.contractsProperties,
270 this.failOnNoContracts).downloadAndUnpackContractsIfRequired(config, this.contractsDirectory);
271 getLog().info("Directory with contract is present at [" + contractsDirectory + "]");
272 throwExceptionWhenFailOnNoContracts(contractsDirectory, this.contractsRepositoryUrl);
273
274 if (this.incrementalContractTests
275 && !ChangeDetector.inputFilesChangeDetected(contractsDirectory, mojoExecution, session)) {
276 getLog().info("Nothing to generate - all classes are up to date");
277 return;
278 }
279
280 setupConfig(config, contractsDirectory);
281 this.project.addTestCompileSourceRoot(this.generatedTestSourcesDir.getAbsolutePath());
282 Resource resource = new Resource();
283 resource.setDirectory(this.generatedTestResourcesDir.getAbsolutePath());
284 this.project.addTestResource(resource);
285 if (getLog().isInfoEnabled()) {
286 getLog().info("Test Source directory: " + this.generatedTestSourcesDir.getAbsolutePath() + " added.");
287 getLog().info("Using [" + config.getBaseClassForTests() + "] as base class for test classes, ["
288 + config.getBasePackageForTests() + "] as base " + "package for tests, ["
289 + config.getPackageWithBaseClasses() + "] as package with " + "base classes, base class mappings "
290 + this.baseClassMappings);
291 }
292 try {
293 LeftOverPrevention leftOverPrevention = new LeftOverPrevention(this.generatedTestSourcesDir, mojoExecution,
294 session);
295 TestGenerator generator = new TestGenerator(config);
296 int generatedClasses = generator.generate();
297 getLog().info("Generated " + generatedClasses + " test classes.");
298 leftOverPrevention.deleteLeftOvers();
299 }
300 catch (ContractVerifierException e) {
301 throw new MojoExecutionException(
302 String.format("Spring Cloud Contract Verifier Plugin exception: %s", e.getMessage()), e);
303 }
304 }
305
306 private void throwExceptionWhenFailOnNoContracts(File file, String contractsRepository)
307 throws MojoExecutionException {
308 if (StringUtils.hasText(contractsRepository)) {
309 if (getLog().isDebugEnabled()) {
310 getLog().debug(
311 "Contracts repository is set, will not throw an exception that the contracts are not found");
312 }
313 return;
314 }
315 if (this.failOnNoContracts && (!file.exists() || file.listFiles().length == 0)) {
316 String path = file.getAbsolutePath();
317 throw new MojoExecutionException("Contracts could not be found: [" + path
318 + "]\nPlease make sure that the contracts were defined, or set the [failOnNoContracts] property to [false]");
319 }
320 }
321
322 private void setupConfig(ContractVerifierConfigProperties config, File contractsDirectory) {
323 config.setContractsDslDir(contractsDirectory);
324 config.setGeneratedTestSourcesDir(this.generatedTestSourcesDir);
325 config.setGeneratedTestResourcesDir(this.generatedTestResourcesDir);
326 config.setTestFramework(this.testFramework);
327 config.setTestMode(this.testMode);
328 config.setBasePackageForTests(this.basePackageForTests);
329 config.setBaseClassForTests(this.baseClassForTests);
330 config.setRuleClassForTests(this.ruleClassForTests);
331 config.setNameSuffixForTests(this.nameSuffixForTests);
332 config.setImports(this.imports);
333 config.setStaticImports(this.staticImports);
334 config.setIgnoredFiles(this.ignoredFiles);
335 config.setExcludedFiles(this.excludedFiles);
336 config.setIncludedFiles(this.includedFiles);
337 config.setAssertJsonSize(this.assertJsonSize);
338 config.setPackageWithBaseClasses(this.packageWithBaseClasses);
339 if (this.baseClassMappings != null) {
340 config.setBaseClassMappings(mappingsToMap());
341 }
342 }
343
344 public Map<String, String> mappingsToMap() {
345 Map<String, String> map = new HashMap<>();
346 if (this.baseClassMappings == null) {
347 return map;
348 }
349 for (BaseClassMapping mapping : this.baseClassMappings) {
350 map.put(mapping.getContractPackageRegex(), mapping.getBaseClassFQN());
351 }
352 return map;
353 }
354
355 public List<String> getExcludedFiles() {
356 return this.excludedFiles;
357 }
358
359 public void setExcludedFiles(List<String> excludedFiles) {
360 this.excludedFiles = excludedFiles;
361 }
362
363 public List<String> getIgnoredFiles() {
364 return this.ignoredFiles;
365 }
366
367 public void setIgnoredFiles(List<String> ignoredFiles) {
368 this.ignoredFiles = ignoredFiles;
369 }
370
371 public boolean isAssertJsonSize() {
372 return this.assertJsonSize;
373 }
374
375 public void setAssertJsonSize(boolean assertJsonSize) {
376 this.assertJsonSize = assertJsonSize;
377 }
378
379 }