1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.eluder.coveralls.maven.plugin;
25
26 import static org.junit.jupiter.api.Assertions.assertEquals;
27 import static org.junit.jupiter.api.Assertions.assertNotNull;
28 import static org.junit.jupiter.api.Assertions.assertThrows;
29 import static org.junit.jupiter.api.Assertions.assertTrue;
30 import static org.junit.jupiter.api.Assertions.fail;
31 import static org.mockito.ArgumentMatchers.any;
32 import static org.mockito.ArgumentMatchers.anyString;
33 import static org.mockito.Mockito.lenient;
34 import static org.mockito.Mockito.when;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.verifyNoInteractions;
37
38 import java.io.File;
39 import java.io.FileNotFoundException;
40 import java.io.IOException;
41 import java.nio.file.Files;
42 import java.nio.file.Path;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Collections;
46 import java.util.List;
47
48 import org.apache.maven.model.Build;
49 import org.apache.maven.model.Model;
50 import org.apache.maven.model.Reporting;
51 import org.apache.maven.plugin.MojoExecutionException;
52 import org.apache.maven.plugin.MojoFailureException;
53 import org.apache.maven.plugin.logging.Log;
54 import org.apache.maven.project.MavenProject;
55 import org.apache.maven.settings.Settings;
56 import org.eluder.coveralls.maven.plugin.domain.CoverallsResponse;
57 import org.eluder.coveralls.maven.plugin.domain.Git;
58 import org.eluder.coveralls.maven.plugin.domain.Job;
59 import org.eluder.coveralls.maven.plugin.domain.Source;
60 import org.eluder.coveralls.maven.plugin.httpclient.CoverallsClient;
61 import org.eluder.coveralls.maven.plugin.json.JsonWriter;
62 import org.eluder.coveralls.maven.plugin.parser.CoberturaParser;
63 import org.eluder.coveralls.maven.plugin.service.ServiceSetup;
64 import org.eluder.coveralls.maven.plugin.source.SourceLoader;
65 import org.eluder.coveralls.maven.plugin.util.TestIoUtil;
66 import org.eluder.coveralls.maven.plugin.validation.ValidationErrors;
67 import org.junit.jupiter.api.BeforeEach;
68 import org.junit.jupiter.api.Test;
69 import org.junit.jupiter.api.extension.ExtendWith;
70 import org.junit.jupiter.api.io.CleanupMode;
71 import org.junit.jupiter.api.io.TempDir;
72 import org.mockito.Mock;
73 import org.mockito.Mockito;
74 import org.mockito.invocation.InvocationOnMock;
75 import org.mockito.junit.jupiter.MockitoExtension;
76 import org.mockito.stubbing.Answer;
77
78 @ExtendWith(MockitoExtension.class)
79 public class CoverallsReportMojoTest {
80
81 @TempDir(cleanup = CleanupMode.ON_SUCCESS)
82 public Path folder;
83
84 public File coverallsFile;
85
86 private CoverallsReportMojo mojo;
87
88 @Mock
89 private CoverallsClient coverallsClientMock;
90
91 @Mock
92 private SourceLoader sourceLoaderMock;
93
94 @Mock
95 private Job jobMock;
96
97 @Mock
98 private Log logMock;
99
100 @Mock
101 private MavenProject projectMock;
102
103 @Mock
104 private MavenProject collectedProjectMock;
105
106 @Mock
107 private Model modelMock;
108
109 @Mock
110 private Reporting reportingMock;
111
112 @Mock
113 private Build buildMock;
114
115 @Mock
116 private Settings settingsMock;
117
118 @BeforeEach
119 void init() throws IOException {
120 coverallsFile = Files.createFile(folder.resolve("coverallsFile.json")).toFile();
121
122 lenient().when(sourceLoaderMock.load(anyString())).then(new Answer<Source>() {
123 @Override
124 public Source answer(final InvocationOnMock invocation) throws IOException {
125 String sourceFile = invocation.getArguments()[0].toString();
126 String content = readFileContent(sourceFile);
127 return new Source(sourceFile, content, TestIoUtil.getSha512DigestHex(content));
128 }
129 });
130 lenient().when(logMock.isInfoEnabled()).thenReturn(true);
131 lenient().when(jobMock.validate()).thenReturn(new ValidationErrors());
132
133
134 mojo = new CoverallsReportMojo() {
135 @Override
136 protected SourceLoader createSourceLoader(final Job job) {
137 return sourceLoaderMock;
138 }
139 @Override
140 protected List<CoverageParser> createCoverageParsers(SourceLoader sourceLoader) {
141 List<CoverageParser> parsers = new ArrayList<CoverageParser>();
142 parsers.add(new CoberturaParser(TestIoUtil.getFile("cobertura.xml"), sourceLoader));
143 return parsers;
144 }
145 @Override
146 protected Environment createEnvironment() {
147 return new Environment(this, Collections.<ServiceSetup>emptyList());
148 }
149 @Override
150 protected Job createJob() {
151 return jobMock;
152 }
153 @Override
154 protected JsonWriter createJsonWriter(final Job job) throws IOException {
155 return new JsonWriter(jobMock, CoverallsReportMojoTest.this.coverallsFile);
156 }
157 @Override
158 protected CoverallsClient createCoverallsClient() {
159 return coverallsClientMock;
160 }
161 @Override
162 public Log getLog() {
163 return logMock;
164 }
165 };
166 mojo.settings = settingsMock;
167 mojo.project = projectMock;
168 mojo.sourceEncoding = "UTF-8";
169 mojo.failOnServiceError = true;
170
171 lenient().when(modelMock.getReporting()).thenReturn(reportingMock);
172 lenient().when(reportingMock.getOutputDirectory()).thenReturn(folder.toFile().getAbsolutePath());
173 lenient().when(buildMock.getDirectory()).thenReturn(folder.toFile().getAbsolutePath());
174
175 List<MavenProject> projects = new ArrayList<MavenProject>();
176 projects.add(collectedProjectMock);
177 lenient().when(projectMock.getCollectedProjects()).thenReturn(projects);
178 lenient().when(projectMock.getBuild()).thenReturn(buildMock);
179 lenient().when(projectMock.getModel()).thenReturn(modelMock);
180 List<String> sourceRoots = new ArrayList<String>();
181 sourceRoots.add(folder.toFile().getAbsolutePath());
182 lenient().when(collectedProjectMock.getCompileSourceRoots()).thenReturn(sourceRoots);
183 lenient().when(collectedProjectMock.getBuild()).thenReturn(buildMock);
184 lenient().when(collectedProjectMock.getModel()).thenReturn(modelMock);
185 }
186
187 @Test
188 void testCreateCoverageParsersWithoutCoverageReports() {
189 mojo = new CoverallsReportMojo();
190 mojo.settings = settingsMock;
191 mojo.project = projectMock;
192 assertThrows(IOException.class, () -> {
193 mojo.createCoverageParsers(sourceLoaderMock);
194 });
195 }
196
197 @Test
198 void testCreateSourceLoader() throws IOException {
199 Git gitMock = Mockito.mock(Git.class);
200 Path git = Files.createDirectory(folder.resolve("git"));
201 when(gitMock.getBaseDir()).thenReturn(git.toFile());
202 when(jobMock.getGit()).thenReturn(gitMock);
203 TestIoUtil.writeFileContent("public interface Test { }", Files.createFile(git.resolve("source.java")).toFile());
204 mojo = new CoverallsReportMojo();
205 mojo.settings = settingsMock;
206 mojo.project = projectMock;
207 mojo.sourceEncoding = "UTF-8";
208 SourceLoader sourceLoader = mojo.createSourceLoader(jobMock);
209 Source source = sourceLoader.load("git/source.java");
210 assertNotNull(source);
211 }
212
213 @Test
214 void testDefaultBehavior() throws IOException, MojoExecutionException, MojoFailureException {
215 mojo = new CoverallsReportMojo() {
216 @Override
217 protected SourceLoader createSourceLoader(final Job job) {
218 return sourceLoaderMock;
219 }
220 @Override
221 protected List<CoverageParser> createCoverageParsers(SourceLoader sourceLoader) throws IOException {
222 return Collections.emptyList();
223 }
224 };
225 mojo.sourceDirectories = Arrays.asList(TestIoUtil.getFile("/"));
226 mojo.sourceEncoding = "UTF-8";
227 mojo.settings = settingsMock;
228 mojo.project = projectMock;
229 mojo.repoToken = "asdfg";
230 mojo.coverallsFile = Files.createFile(folder.resolve("mojoCoverallsFile")).toFile();
231 mojo.dryRun = true;
232 mojo.skip = false;
233 mojo.basedir = TestIoUtil.getFile("/");
234
235 mojo.execute();
236 }
237
238 @Test
239 void testSuccessfullSubmission() throws ProcessingException, IOException, MojoExecutionException, MojoFailureException {
240 when(coverallsClientMock.submit(any(File.class))).thenReturn(new CoverallsResponse("success", false, null));
241 mojo.execute();
242 String json = TestIoUtil.readFileContent(coverallsFile);
243 assertNotNull(json);
244
245 String[][] fixture = CoverageFixture.JAVA_FILES;
246 for (String[] coverageFile : fixture) {
247 assertTrue(json.contains(coverageFile[0]));
248 }
249
250 verifySuccessfullSubmit(logMock, fixture);
251 }
252
253 @Test
254 void testFailWithProcessingException() throws ProcessingException, IOException, MojoExecutionException {
255 when(coverallsClientMock.submit(any(File.class))).thenThrow(new ProcessingException());
256 try {
257 mojo.execute();
258 fail("Should have failed with MojoFailureException");
259 } catch (MojoFailureException ex) {
260 assertEquals(ex.getCause().getClass(), ProcessingException.class);
261 }
262 }
263
264 @Test
265 void testProcessingExceptionWithAllowedServiceFailure() throws ProcessingException, IOException, MojoExecutionException {
266 mojo.failOnServiceError = false;
267 when(coverallsClientMock.submit(any(File.class))).thenThrow(new ProcessingException());
268 try {
269 mojo.execute();
270 fail("Should have failed with MojoFailureException");
271 } catch (MojoFailureException ex) {
272 assertEquals(ex.getCause().getClass(), ProcessingException.class);
273 }
274 }
275
276 @Test
277 void testFailWithIOException() throws ProcessingException, IOException, MojoExecutionException {
278 when(coverallsClientMock.submit(any(File.class))).thenThrow(new IOException());
279 try {
280 mojo.execute();
281 fail("Should have failed with MojoFailureException");
282 } catch (MojoFailureException ex) {
283 assertEquals(ex.getCause().getClass(), IOException.class);
284 }
285 }
286
287 @Test
288 void testIOExceptionWithAllowedServiceFailure() throws ProcessingException, IOException, MojoExecutionException, MojoFailureException {
289 mojo.failOnServiceError = false;
290 when(coverallsClientMock.submit(any(File.class))).thenThrow(new IOException());
291 mojo.execute();
292 verify(logMock).warn(anyString());
293 }
294
295 @Test
296 void testFailWithNullPointerException() throws ProcessingException, IOException, MojoFailureException {
297 when(coverallsClientMock.submit(any(File.class))).thenThrow(new NullPointerException());
298 try {
299 mojo.execute();
300 fail("Should have failed with MojoFailureException");
301 } catch (MojoExecutionException ex) {
302 assertEquals(ex.getCause().getClass(), NullPointerException.class);
303 }
304 }
305
306 @Test
307 void testSkipExecution() throws MojoExecutionException, MojoFailureException {
308 mojo.skip = true;
309 mojo.execute();
310
311 verifyNoInteractions(jobMock);
312 }
313
314 public static void verifySuccessfullSubmit(Log logMock, String[][] fixture) {
315 verify(logMock).info("Gathered code coverage metrics for " + CoverageFixture.getTotalFiles(fixture) + " source files with " + CoverageFixture.getTotalLines(fixture) + " lines of code:");
316 verify(logMock).info("*** It might take hours for Coveralls to update the actual coverage numbers for a job");
317 }
318
319 protected String readFileContent(final String sourceFile) throws FileNotFoundException, IOException {
320 return TestIoUtil.readFileContent(TestIoUtil.getFile(sourceFile));
321 }
322 }