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 @Parameter(property = "skipTests", defaultValue = "false")
134 private boolean skipTests;
135
136
137
138
139
140
141 @Parameter(property = "contractsRepositoryUrl")
142 private String contractsRepositoryUrl;
143
144 @Parameter(property = "contractDependency")
145 private Dependency contractDependency;
146
147
148
149
150
151
152
153 @Parameter(property = "contractsPath")
154 private String contractsPath;
155
156
157
158
159 @Parameter(property = "contractsMode", defaultValue = "CLASSPATH")
160 private StubRunnerProperties.StubsMode contractsMode;
161
162
163
164
165
166
167
168
169
170
171 @Parameter(property = "packageWithBaseClasses")
172 private String packageWithBaseClasses;
173
174
175
176
177
178
179
180
181
182 @Parameter(property = "baseClassMappings")
183 private List<BaseClassMapping> baseClassMappings;
184
185
186
187
188 @Parameter(property = "contractsRepositoryUsername")
189 private String contractsRepositoryUsername;
190
191
192
193
194 @Parameter(property = "contractsRepositoryPassword")
195 private String contractsRepositoryPassword;
196
197
198
199
200 @Parameter(property = "contractsRepositoryProxyHost")
201 private String contractsRepositoryProxyHost;
202
203
204
205
206 @Parameter(property = "contractsRepositoryProxyPort")
207 private Integer contractsRepositoryProxyPort;
208
209
210
211
212
213 @Parameter(property = "deleteStubsAfterTest", defaultValue = "true")
214 private boolean deleteStubsAfterTest;
215
216
217
218
219
220 @Parameter(property = "contractsProperties")
221 private Map<String, String> contractsProperties = new HashMap<>();
222
223
224
225
226
227 @Parameter(property = "failOnNoContracts", defaultValue = "true")
228 private boolean failOnNoContracts;
229
230
231
232
233
234
235
236 @Parameter(property = "failOnInProgress", defaultValue = "true")
237 private boolean failOnInProgress = true;
238
239
240
241
242
243 @Parameter(property = "incrementalContractTests", defaultValue = "true")
244 private boolean incrementalContractTests = true;
245
246 @Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true)
247 private MojoExecution mojoExecution;
248
249 @Parameter(defaultValue = "${session}", readonly = true, required = true)
250 private MavenSession session;
251
252 @Override
253 public void execute() throws MojoExecutionException, MojoFailureException {
254 if (this.skip || this.mavenTestSkip || this.skipTests) {
255 if (this.skip) {
256 getLog().info("Skipping Spring Cloud Contract Verifier execution: spring.cloud.contract.verifier.skip="
257 + this.skip);
258 }
259 if (this.mavenTestSkip) {
260 getLog().info(
261 "Skipping Spring Cloud Contract Verifier execution: maven.test.skip=" + this.mavenTestSkip);
262 }
263 if (this.skipTests) {
264 getLog().info("Skipping Spring Cloud Contract Verifier execution: skipTests" + this.skipTests);
265 }
266 return;
267 }
268 getLog().info("Generating server tests source code for Spring Cloud Contract Verifier contract verification");
269 final ContractVerifierConfigProperties config = new ContractVerifierConfigProperties();
270 config.setFailOnInProgress(this.failOnInProgress);
271
272 File contractsDirectory = new MavenContractsDownloader(this.project, this.contractDependency,
273 this.contractsPath, this.contractsRepositoryUrl, this.contractsMode, getLog(),
274 this.contractsRepositoryUsername, this.contractsRepositoryPassword, this.contractsRepositoryProxyHost,
275 this.contractsRepositoryProxyPort, this.deleteStubsAfterTest, this.contractsProperties,
276 this.failOnNoContracts).downloadAndUnpackContractsIfRequired(config, this.contractsDirectory);
277 getLog().info("Directory with contract is present at [" + contractsDirectory + "]");
278 throwExceptionWhenFailOnNoContracts(contractsDirectory, this.contractsRepositoryUrl);
279
280 if (this.incrementalContractTests
281 && !ChangeDetector.inputFilesChangeDetected(contractsDirectory, mojoExecution, session)) {
282 getLog().info("Nothing to generate - all classes are up to date");
283 return;
284 }
285
286 setupConfig(config, contractsDirectory);
287 this.project.addTestCompileSourceRoot(this.generatedTestSourcesDir.getAbsolutePath());
288 Resource resource = new Resource();
289 resource.setDirectory(this.generatedTestResourcesDir.getAbsolutePath());
290 this.project.addTestResource(resource);
291 if (getLog().isInfoEnabled()) {
292 getLog().info("Test Source directory: " + this.generatedTestSourcesDir.getAbsolutePath() + " added.");
293 getLog().info("Using [" + config.getBaseClassForTests() + "] as base class for test classes, ["
294 + config.getBasePackageForTests() + "] as base " + "package for tests, ["
295 + config.getPackageWithBaseClasses() + "] as package with " + "base classes, base class mappings "
296 + this.baseClassMappings);
297 }
298 try {
299 LeftOverPrevention leftOverPrevention = new LeftOverPrevention(this.generatedTestSourcesDir, mojoExecution,
300 session);
301 TestGenerator generator = new TestGenerator(config);
302 int generatedClasses = generator.generate();
303 getLog().info("Generated " + generatedClasses + " test classes.");
304 leftOverPrevention.deleteLeftOvers();
305 }
306 catch (ContractVerifierException e) {
307 throw new MojoExecutionException(
308 String.format("Spring Cloud Contract Verifier Plugin exception: %s", e.getMessage()), e);
309 }
310 }
311
312 private void throwExceptionWhenFailOnNoContracts(File file, String contractsRepository)
313 throws MojoExecutionException {
314 if (StringUtils.hasText(contractsRepository)) {
315 if (getLog().isDebugEnabled()) {
316 getLog().debug(
317 "Contracts repository is set, will not throw an exception that the contracts are not found");
318 }
319 return;
320 }
321 if (this.failOnNoContracts && (!file.exists() || file.listFiles().length == 0)) {
322 String path = file.getAbsolutePath();
323 throw new MojoExecutionException("Contracts could not be found: [" + path
324 + "]\nPlease make sure that the contracts were defined, or set the [failOnNoContracts] property to [false]");
325 }
326 }
327
328 private void setupConfig(ContractVerifierConfigProperties config, File contractsDirectory) {
329 config.setContractsDslDir(contractsDirectory);
330 config.setGeneratedTestSourcesDir(this.generatedTestSourcesDir);
331 config.setGeneratedTestResourcesDir(this.generatedTestResourcesDir);
332 config.setTestFramework(this.testFramework);
333 config.setTestMode(this.testMode);
334 config.setBasePackageForTests(this.basePackageForTests);
335 config.setBaseClassForTests(this.baseClassForTests);
336 config.setRuleClassForTests(this.ruleClassForTests);
337 config.setNameSuffixForTests(this.nameSuffixForTests);
338 config.setImports(this.imports);
339 config.setStaticImports(this.staticImports);
340 config.setIgnoredFiles(this.ignoredFiles);
341 config.setExcludedFiles(this.excludedFiles);
342 config.setIncludedFiles(this.includedFiles);
343 config.setAssertJsonSize(this.assertJsonSize);
344 config.setPackageWithBaseClasses(this.packageWithBaseClasses);
345 if (this.baseClassMappings != null) {
346 config.setBaseClassMappings(mappingsToMap());
347 }
348 }
349
350 public Map<String, String> mappingsToMap() {
351 Map<String, String> map = new HashMap<>();
352 if (this.baseClassMappings == null) {
353 return map;
354 }
355 for (BaseClassMapping mapping : this.baseClassMappings) {
356 map.put(mapping.getContractPackageRegex(), mapping.getBaseClassFQN());
357 }
358 return map;
359 }
360
361 public List<String> getExcludedFiles() {
362 return this.excludedFiles;
363 }
364
365 public void setExcludedFiles(List<String> excludedFiles) {
366 this.excludedFiles = excludedFiles;
367 }
368
369 public List<String> getIgnoredFiles() {
370 return this.ignoredFiles;
371 }
372
373 public void setIgnoredFiles(List<String> ignoredFiles) {
374 this.ignoredFiles = ignoredFiles;
375 }
376
377 public boolean isAssertJsonSize() {
378 return this.assertJsonSize;
379 }
380
381 public void setAssertJsonSize(boolean assertJsonSize) {
382 this.assertJsonSize = assertJsonSize;
383 }
384
385 }