1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.eluder.coveralls.maven.plugin;
26
27 import java.io.File;
28 import java.io.IOException;
29 import java.nio.file.Files;
30 import java.nio.file.Path;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.List;
34
35 import org.apache.maven.model.Build;
36 import org.apache.maven.model.Model;
37 import org.apache.maven.model.Reporting;
38 import org.apache.maven.plugin.MojoExecutionException;
39 import org.apache.maven.plugin.MojoFailureException;
40 import org.apache.maven.plugin.logging.Log;
41 import org.apache.maven.project.MavenProject;
42 import org.apache.maven.settings.Settings;
43 import org.eluder.coveralls.maven.plugin.domain.CoverallsResponse;
44 import org.eluder.coveralls.maven.plugin.domain.Git;
45 import org.eluder.coveralls.maven.plugin.domain.Job;
46 import org.eluder.coveralls.maven.plugin.domain.Source;
47 import org.eluder.coveralls.maven.plugin.httpclient.CoverallsClient;
48 import org.eluder.coveralls.maven.plugin.json.JsonWriter;
49 import org.eluder.coveralls.maven.plugin.parser.CoberturaParser;
50 import org.eluder.coveralls.maven.plugin.source.SourceLoader;
51 import org.eluder.coveralls.maven.plugin.util.TestIoUtil;
52 import org.eluder.coveralls.maven.plugin.validation.ValidationErrors;
53 import org.junit.jupiter.api.Assertions;
54 import org.junit.jupiter.api.BeforeEach;
55 import org.junit.jupiter.api.Test;
56 import org.junit.jupiter.api.extension.ExtendWith;
57 import org.junit.jupiter.api.io.CleanupMode;
58 import org.junit.jupiter.api.io.TempDir;
59 import org.mockito.ArgumentMatchers;
60 import org.mockito.Mock;
61 import org.mockito.Mockito;
62 import org.mockito.junit.jupiter.MockitoExtension;
63
64
65
66
67 @ExtendWith(MockitoExtension.class)
68 class CoverallsReportMojoTest {
69
70
71 @TempDir(cleanup = CleanupMode.ON_SUCCESS)
72 Path folder;
73
74
75 File coverallsFile;
76
77
78 CoverallsReportMojo mojo;
79
80
81 @Mock
82 CoverallsClient coverallsClientMock;
83
84
85 @Mock
86 SourceLoader sourceLoaderMock;
87
88
89 @Mock
90 Job jobMock;
91
92
93 @Mock
94 Log logMock;
95
96
97 @Mock
98 MavenProject projectMock;
99
100
101 @Mock
102 MavenProject collectedProjectMock;
103
104
105 @Mock
106 Model modelMock;
107
108
109 @Mock
110 Reporting reportingMock;
111
112
113 @Mock
114 Build buildMock;
115
116
117 @Mock
118 Settings settingsMock;
119
120
121
122
123
124
125
126 @BeforeEach
127 void init() throws IOException {
128 this.coverallsFile = Files.createFile(this.folder.resolve("coverallsFile.json")).toFile();
129
130 Mockito.lenient().when(this.sourceLoaderMock.load(ArgumentMatchers.anyString())).then(invocation -> {
131 final var sourceFile = invocation.getArguments()[0].toString();
132 final var content = this.readFileContent(sourceFile);
133 return new Source(sourceFile, content, TestIoUtil.getSha512DigestHex(content));
134 });
135 Mockito.lenient().when(this.logMock.isInfoEnabled()).thenReturn(true);
136 Mockito.lenient().when(this.jobMock.validate()).thenReturn(new ValidationErrors());
137
138 this.mojo = new CoverallsReportMojo() {
139 @Override
140 protected SourceLoader createSourceLoader(final Job job) {
141 return CoverallsReportMojoTest.this.sourceLoaderMock;
142 }
143
144 @Override
145 protected List<CoverageParser> createCoverageParsers(SourceLoader sourceLoader) {
146 final List<CoverageParser> parsers = new ArrayList<>();
147 parsers.add(new CoberturaParser(TestIoUtil.getFile("cobertura.xml"), sourceLoader));
148 return parsers;
149 }
150
151 @Override
152 protected Environment createEnvironment() {
153 return new Environment(this, List.of());
154 }
155
156 @Override
157 protected Job createJob() {
158 return CoverallsReportMojoTest.this.jobMock;
159 }
160
161 @Override
162 protected JsonWriter createJsonWriter(final Job job) throws IOException {
163 return new JsonWriter(CoverallsReportMojoTest.this.jobMock, CoverallsReportMojoTest.this.coverallsFile);
164 }
165
166 @Override
167 protected CoverallsClient createCoverallsClient() {
168 return CoverallsReportMojoTest.this.coverallsClientMock;
169 }
170
171 @Override
172 public Log getLog() {
173 return CoverallsReportMojoTest.this.logMock;
174 }
175 };
176 this.mojo.settings = this.settingsMock;
177 this.mojo.project = this.projectMock;
178 this.mojo.sourceEncoding = "UTF-8";
179 this.mojo.failOnServiceError = true;
180
181 Mockito.lenient().when(this.modelMock.getReporting()).thenReturn(this.reportingMock);
182 Mockito.lenient().when(this.reportingMock.getOutputDirectory())
183 .thenReturn(this.folder.toFile().getAbsolutePath());
184 Mockito.lenient().when(this.buildMock.getDirectory()).thenReturn(this.folder.toFile().getAbsolutePath());
185
186 final List<MavenProject> projects = new ArrayList<>();
187 projects.add(this.collectedProjectMock);
188 Mockito.lenient().when(this.projectMock.getCollectedProjects()).thenReturn(projects);
189 Mockito.lenient().when(this.projectMock.getBuild()).thenReturn(this.buildMock);
190 Mockito.lenient().when(this.projectMock.getModel()).thenReturn(this.modelMock);
191 final List<String> sourceRoots = new ArrayList<>();
192 sourceRoots.add(this.folder.toFile().getAbsolutePath());
193 Mockito.lenient().when(this.collectedProjectMock.getCompileSourceRoots()).thenReturn(sourceRoots);
194 Mockito.lenient().when(this.collectedProjectMock.getBuild()).thenReturn(this.buildMock);
195 Mockito.lenient().when(this.collectedProjectMock.getModel()).thenReturn(this.modelMock);
196 }
197
198
199
200
201 @Test
202 void createCoverageParsersWithoutCoverageReports() {
203 this.mojo = new CoverallsReportMojo();
204 this.mojo.settings = this.settingsMock;
205 this.mojo.project = this.projectMock;
206 Assertions.assertThrows(IOException.class, () -> this.mojo.createCoverageParsers(this.sourceLoaderMock));
207 }
208
209
210
211
212
213
214
215 @Test
216 void createSourceLoader() throws IOException {
217 final var gitMock = Mockito.mock(Git.class);
218 final var git = Files.createDirectory(this.folder.resolve("git"));
219 Mockito.when(gitMock.getBaseDir()).thenReturn(git.toFile());
220 Mockito.when(this.jobMock.getGit()).thenReturn(gitMock);
221 TestIoUtil.writeFileContent("public interface Test { }", Files.createFile(git.resolve("source.java")).toFile());
222 this.mojo = new CoverallsReportMojo();
223 this.mojo.settings = this.settingsMock;
224 this.mojo.project = this.projectMock;
225 this.mojo.sourceEncoding = "UTF-8";
226 final var sourceLoader = this.mojo.createSourceLoader(this.jobMock);
227 final var source = sourceLoader.load("git/source.java");
228 Assertions.assertNotNull(source);
229 }
230
231
232
233
234
235
236
237
238
239
240
241 @Test
242 void defaultBehavior() throws IOException, MojoExecutionException, MojoFailureException {
243 this.mojo = new CoverallsReportMojo() {
244 @Override
245 protected SourceLoader createSourceLoader(final Job job) {
246 return CoverallsReportMojoTest.this.sourceLoaderMock;
247 }
248
249 @Override
250 protected List<CoverageParser> createCoverageParsers(SourceLoader sourceLoader) throws IOException {
251 return List.of();
252 }
253 };
254 this.mojo.sourceDirectories = Arrays.asList(TestIoUtil.getFile("/"));
255 this.mojo.sourceEncoding = "UTF-8";
256 this.mojo.settings = this.settingsMock;
257 this.mojo.project = this.projectMock;
258 this.mojo.repoToken = "asdfg";
259 this.mojo.coverallsFile = Files.createFile(this.folder.resolve("mojoCoverallsFile")).toFile();
260 this.mojo.dryRun = true;
261 this.mojo.skip = false;
262 this.mojo.basedir = TestIoUtil.getFile("/");
263
264 Assertions.assertDoesNotThrow(() -> this.mojo.execute());
265 }
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281 @Test
282 void successfulSubmission() throws ProcessingException, IOException, MojoExecutionException, MojoFailureException,
283 InterruptedException {
284 Mockito.when(this.coverallsClientMock.submit(ArgumentMatchers.any(File.class)))
285 .thenReturn(new CoverallsResponse("success", false, null));
286 this.mojo.execute();
287 final var json = TestIoUtil.readFileContent(this.coverallsFile);
288 Assertions.assertNotNull(json);
289
290 final var fixture = CoverageFixture.JAVA_FILES;
291 for (final List<String> coverageFile : fixture) {
292 Assertions.assertTrue(json.contains(coverageFile.get(0)));
293 }
294
295 CoverallsReportMojoTest.verifySuccessfulSubmit(this.logMock, fixture);
296 }
297
298
299
300
301
302
303
304
305
306
307
308
309
310 @Test
311 void failWithProcessingException()
312 throws ProcessingException, IOException, MojoExecutionException, InterruptedException {
313 Mockito.when(this.coverallsClientMock.submit(ArgumentMatchers.any(File.class)))
314 .thenThrow(new ProcessingException());
315 try {
316 this.mojo.execute();
317 Assertions.fail("Should have failed with MojoFailureException");
318 } catch (final MojoFailureException e) {
319 Assertions.assertEquals(ProcessingException.class, e.getCause().getClass());
320 }
321 }
322
323
324
325
326
327
328
329
330
331
332
333
334
335 @Test
336 void processingExceptionWithAllowedServiceFailure()
337 throws ProcessingException, IOException, MojoExecutionException, InterruptedException {
338 this.mojo.failOnServiceError = false;
339 Mockito.when(this.coverallsClientMock.submit(ArgumentMatchers.any(File.class)))
340 .thenThrow(new ProcessingException());
341 try {
342 this.mojo.execute();
343 Assertions.fail("Should have failed with MojoFailureException");
344 } catch (final MojoFailureException e) {
345 Assertions.assertEquals(ProcessingException.class, e.getCause().getClass());
346 }
347 }
348
349
350
351
352
353
354
355
356
357
358
359
360
361 @Test
362 void failWithIOException() throws ProcessingException, IOException, MojoExecutionException, InterruptedException {
363 Mockito.when(this.coverallsClientMock.submit(ArgumentMatchers.any(File.class))).thenThrow(new IOException());
364 try {
365 this.mojo.execute();
366 Assertions.fail("Should have failed with MojoFailureException");
367 } catch (final MojoFailureException ex) {
368 Assertions.assertEquals(IOException.class, ex.getCause().getClass());
369 }
370 }
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386 @Test
387 void ioExceptionWithAllowedServiceFailure() throws ProcessingException, IOException, MojoExecutionException,
388 MojoFailureException, InterruptedException {
389 this.mojo.failOnServiceError = false;
390 Mockito.when(this.coverallsClientMock.submit(ArgumentMatchers.any(File.class))).thenThrow(new IOException());
391 this.mojo.execute();
392 Mockito.verify(this.logMock).warn(ArgumentMatchers.anyString());
393 }
394
395
396
397
398
399
400
401
402
403
404
405
406
407 @Test
408 void failWithNullPointerException()
409 throws ProcessingException, IOException, MojoFailureException, InterruptedException {
410 Mockito.when(this.coverallsClientMock.submit(ArgumentMatchers.any(File.class)))
411 .thenThrow(new NullPointerException());
412 try {
413 this.mojo.execute();
414 Assertions.fail("Should have failed with MojoFailureException");
415 } catch (final MojoExecutionException e) {
416 Assertions.assertEquals(NullPointerException.class, e.getCause().getClass());
417 }
418 }
419
420
421
422
423
424
425
426
427
428 @Test
429 void skipExecution() throws MojoExecutionException, MojoFailureException {
430 this.mojo.skip = true;
431 this.mojo.execute();
432
433 Mockito.verifyNoInteractions(this.jobMock);
434 }
435
436
437
438
439
440
441
442
443
444 static void verifySuccessfulSubmit(final Log logMock, final List<List<String>> fixture) {
445 Mockito.verify(logMock, Mockito.times(1))
446 .info("Gathered code coverage metrics for " + CoverageFixture.getTotalFiles(fixture)
447 + " source files with " + CoverageFixture.getTotalLines(fixture) + " lines of code:");
448 Mockito.verify(logMock, Mockito.times(1))
449 .info("*** Coverage results are usually available immediately on Coveralls.");
450 }
451
452
453
454
455
456
457
458
459
460
461
462
463 String readFileContent(final String sourceFile) throws IOException {
464 return TestIoUtil.readFileContent(TestIoUtil.getFile(sourceFile));
465 }
466
467 }