View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugin.surefire;
20  
21  import java.io.File;
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  import org.apache.maven.plugin.MojoExecutionException;
26  import org.apache.maven.plugin.MojoFailureException;
27  import org.apache.maven.plugin.surefire.AbstractSurefireMojoTest.Mojo;
28  import org.apache.maven.plugin.surefire.log.PluginConsoleLogger;
29  import org.apache.maven.surefire.api.suite.RunResult;
30  import org.apache.maven.surefire.api.testset.TestSetFailedException;
31  import org.apache.maven.surefire.booter.SurefireBooterForkException;
32  import org.junit.jupiter.api.Test;
33  import org.mockito.ArgumentCaptor;
34  import org.slf4j.Logger;
35  
36  import static java.util.Collections.addAll;
37  import static java.util.Collections.singleton;
38  import static org.apache.maven.plugin.surefire.SurefireHelper.escapeToPlatformPath;
39  import static org.apache.maven.plugin.surefire.SurefireHelper.reportExecution;
40  import static org.apache.maven.surefire.shared.lang3.SystemUtils.IS_OS_WINDOWS;
41  import static org.assertj.core.api.Assertions.assertThat;
42  import static org.junit.jupiter.api.Assertions.assertThrows;
43  import static org.junit.jupiter.api.Assumptions.assumeTrue;
44  import static org.mockito.ArgumentMatchers.anyString;
45  import static org.mockito.Mockito.doNothing;
46  import static org.mockito.Mockito.mock;
47  import static org.mockito.Mockito.verify;
48  import static org.mockito.Mockito.when;
49  
50  /**
51   * Test of {@link SurefireHelper}.
52   */
53  public class SurefireHelperTest {
54  
55      @Test
56      public void shouldReplaceForkNumberPath() {
57          File root = new File(System.getProperty("user.dir", ""));
58          File pathWithPlaceholder = new File(root, "${surefire.forkNumber}");
59          File changed = SurefireHelper.replaceForkThreadsInPath(pathWithPlaceholder, 5);
60          assertThat(changed.getPath()).isEqualTo(new File(root, "5").getPath());
61      }
62  
63      @Test
64      public void shouldReplaceLongForkNumberPath() {
65          File root = new File(System.getProperty("user.dir", ""));
66          File subDir = new File(root, "reports-${surefire.forkNumber}");
67          File pathWithPlaceholder = new File(subDir, "subdir");
68          File changed = SurefireHelper.replaceForkThreadsInPath(pathWithPlaceholder, 5);
69          assertThat(changed.getPath()).isEqualTo(new File(new File(root, "reports-5"), "subdir").getPath());
70      }
71  
72      @Test
73      public void shouldBeThreeDumpFiles() {
74          String[] dumps = SurefireHelper.getDumpFilesToPrint();
75          assertThat(dumps).hasSize(4);
76          assertThat(dumps).doesNotHaveDuplicates();
77          List<String> onlyStrings = new ArrayList<>();
78          addAll(onlyStrings, dumps);
79          onlyStrings.removeAll(singleton((String) null));
80          assertThat(onlyStrings).hasSize(4);
81      }
82  
83      @Test
84      public void shouldCloneDumpFiles() {
85          String[] dumps1 = SurefireHelper.getDumpFilesToPrint();
86          String[] dumps2 = SurefireHelper.getDumpFilesToPrint();
87          assertThat(dumps1).isNotSameAs(dumps2);
88      }
89  
90      @Test
91      public void testConstants() {
92          assertThat(SurefireHelper.DUMPSTREAM_FILENAME_FORMATTER)
93                  .isEqualTo(SurefireHelper.DUMP_FILE_PREFIX + "%d.dumpstream");
94  
95          assertThat(String.format(SurefireHelper.DUMPSTREAM_FILENAME_FORMATTER, 5))
96                  .endsWith("-jvmRun5.dumpstream");
97      }
98  
99      @Test
100     public void shouldEscapeWindowsPath() {
101         assumeTrue(IS_OS_WINDOWS);
102         String root = "X:\\path\\to\\project\\";
103         String pathToJar = "target\\surefire\\surefirebooter4942721306300108667.jar";
104         @SuppressWarnings("checkstyle:magicnumber")
105         int projectNameLength = 247 - root.length() - pathToJar.length();
106         StringBuilder projectDir = new StringBuilder();
107         for (int i = 0; i < projectNameLength; i++) {
108             projectDir.append('x');
109         }
110         String path = root + projectDir + "\\" + pathToJar;
111         String escaped = escapeToPlatformPath(path);
112         assertThat(escaped).isEqualTo("\\\\?\\" + path);
113 
114         path = root + "\\" + pathToJar;
115         escaped = escapeToPlatformPath(path);
116         assertThat(escaped).isEqualTo(root + "\\" + pathToJar);
117     }
118 
119     @Test
120     public void shouldHandleFailWithoutExitCode() throws Exception {
121         RunResult summary = new RunResult(0, 0, 0, 0);
122         Mojo plugin = new Mojo();
123         plugin.setTestFailureIgnore(true);
124 
125         Logger logger = mock(Logger.class);
126         when(logger.isErrorEnabled()).thenReturn(true);
127         doNothing().when(logger).error(anyString());
128         TestSetFailedException exc = new TestSetFailedException("failure");
129         reportExecution(plugin, summary, new PluginConsoleLogger(logger), exc);
130         ArgumentCaptor<String> errorMessage = ArgumentCaptor.forClass(String.class);
131         verify(logger).error(errorMessage.capture());
132         assertThat(errorMessage.getValue()).contains("failure");
133     }
134 
135     @Test
136     public void shouldHandleFailIfJvmNonZeroExitCode() throws Exception {
137         RunResult summary = new RunResult(0, 0, 0, 0);
138         Mojo plugin = new Mojo();
139         plugin.setTestFailureIgnore(true);
140 
141         SurefireBooterForkException exc = new SurefireBooterForkException("Unrecognized option: -Xxxx");
142         MojoExecutionException ex = assertThrows(
143                 MojoExecutionException.class,
144                 () -> reportExecution(plugin, summary, new PluginConsoleLogger(mock(Logger.class)), exc));
145         assertThat(ex.getMessage()).contains("Unrecognized option: -Xxxx");
146     }
147 
148     @Test
149     public void shouldHandleFailIfNoTests() throws Exception {
150         RunResult summary = new RunResult(0, 0, 0, 0);
151         Mojo plugin = new Mojo();
152         plugin.setFailIfNoTests(true);
153         MojoFailureException ex =
154                 assertThrows(MojoFailureException.class, () -> reportExecution(plugin, summary, null, null));
155         assertThat(ex.getMessage())
156                 .contains("No tests were executed!  (Set -DfailIfNoTests=false to ignore this error.)");
157     }
158 
159     @Test
160     public void shouldHandleTestFailure() throws Exception {
161         RunResult summary = new RunResult(1, 0, 1, 0);
162         MojoFailureException ex =
163                 assertThrows(MojoFailureException.class, () -> reportExecution(new Mojo(), summary, null, null));
164         assertThat(ex.getMessage())
165                 .contains("There are test failures.")
166                 .contains("for the individual test results.")
167                 .contains("[date].dump, [date]-jvmRun[N].dump and [date].dumpstream.");
168     }
169 
170     @Test
171     public void failsIfThereAreTooManyFlakes() throws Exception {
172         RunResult summary = new RunResult(1, 0, 0, 0, 1);
173         Mojo reportParameters = new Mojo();
174         reportParameters.setFailOnFlakeCount(1);
175         MojoFailureException ex =
176                 assertThrows(MojoFailureException.class, () -> reportExecution(reportParameters, summary, null, null));
177         assertThat(ex.getMessage())
178                 .contains("There is 1 flake and failOnFlakeCount is set to 1.")
179                 .contains("for the individual test results.")
180                 .contains("[date].dump, [date]-jvmRun[N].dump and [date].dumpstream.");
181     }
182 
183     @Test
184     public void reportsFailuresAndFlakes() throws Exception {
185         RunResult summary = new RunResult(1, 0, 1, 0, 2);
186         Mojo reportParameters = new Mojo();
187         reportParameters.setFailOnFlakeCount(1);
188         MojoFailureException ex =
189                 assertThrows(MojoFailureException.class, () -> reportExecution(reportParameters, summary, null, null));
190         assertThat(ex.getMessage())
191                 .contains("There are test failures.")
192                 .contains("There are 2 flakes and failOnFlakeCount is set to 1.")
193                 .contains("for the individual test results.")
194                 .contains("[date].dump, [date]-jvmRun[N].dump and [date].dumpstream.");
195     }
196 
197     @Test
198     public void passesIfFlakesAreWithinThreshold() throws Exception {
199         RunResult summary = new RunResult(1, 0, 0, 0, 1);
200         reportExecution(new Mojo(), summary, null, null);
201     }
202 }