1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.surefire.common.junit4;
20
21 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
22 import org.apache.maven.surefire.api.report.OutputReportEntry;
23 import org.apache.maven.surefire.api.report.ReportEntry;
24 import org.apache.maven.surefire.api.report.RunMode;
25 import org.apache.maven.surefire.api.report.SimpleReportEntry;
26 import org.apache.maven.surefire.api.report.StackTraceWriter;
27 import org.apache.maven.surefire.api.report.TestOutputReceiver;
28 import org.apache.maven.surefire.api.report.TestOutputReportEntry;
29 import org.apache.maven.surefire.api.report.TestReportListener;
30 import org.apache.maven.surefire.api.testset.TestSetFailedException;
31 import org.apache.maven.surefire.api.util.internal.ClassMethod;
32 import org.apache.maven.surefire.report.ClassMethodIndexer;
33 import org.apache.maven.surefire.report.RunModeSetter;
34 import org.junit.runner.Description;
35 import org.junit.runner.Result;
36 import org.junit.runner.notification.Failure;
37 import org.junit.runner.notification.RunListener;
38
39 import static org.apache.maven.surefire.api.report.SimpleReportEntry.assumption;
40 import static org.apache.maven.surefire.api.report.SimpleReportEntry.ignored;
41 import static org.apache.maven.surefire.api.report.SimpleReportEntry.withException;
42 import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.isFailureInsideJUnitItself;
43 import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.toClassMethod;
44 import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.getAnnotatedIgnoreValue;
45
46
47
48
49
50 public class JUnit4RunListener extends RunListener implements TestOutputReceiver<OutputReportEntry>, RunModeSetter {
51 protected final ClassMethodIndexer classMethodIndexer = new ClassMethodIndexer();
52 protected final TestReportListener<TestOutputReportEntry> reporter;
53 private volatile RunMode runMode;
54
55
56
57
58
59
60
61
62 private final ThreadLocal<Boolean> failureFlag = new InheritableThreadLocal<>();
63
64
65
66
67
68
69 public JUnit4RunListener(TestReportListener<TestOutputReportEntry> reporter) {
70 this.reporter = reporter;
71 }
72
73 public final ConsoleLogger getConsoleLogger() {
74 return reporter;
75 }
76
77 @Override
78 public void setRunMode(RunMode runMode) {
79 this.runMode = runMode;
80 }
81
82 protected final RunMode getRunMode() {
83 return runMode;
84 }
85
86
87
88
89
90
91
92
93 @Override
94 public void testIgnored(Description description) throws Exception {
95 String reason = getAnnotatedIgnoreValue(description);
96 ClassMethod classMethod = toClassMethod(description);
97 long testRunId = classMethodIndexer.indexClassMethod(classMethod.getClazz(), classMethod.getMethod());
98 reporter.testSkipped(
99 ignored(runMode, testRunId, classMethod.getClazz(), null, classMethod.getMethod(), null, reason));
100 }
101
102
103
104
105
106
107 @Override
108 public void testStarted(Description description) throws Exception {
109 try {
110 reporter.testStarting(createReportEntry(description));
111 } finally {
112 failureFlag.remove();
113 }
114 }
115
116
117
118
119
120
121 @Override
122 @SuppressWarnings({"ThrowableResultOfMethodCallIgnored"})
123 public void testFailure(Failure failure) throws Exception {
124 try {
125 StackTraceWriter stackTrace = createStackTraceWriter(failure);
126 ClassMethod classMethod = toClassMethod(failure.getDescription());
127 long testRunId = classMethodIndexer.indexClassMethod(classMethod.getClazz(), classMethod.getMethod());
128 ReportEntry report = withException(
129 runMode, testRunId, classMethod.getClazz(), null, classMethod.getMethod(), null, stackTrace);
130
131 if (failure.getException() instanceof AssertionError) {
132 reporter.testFailed(report);
133 } else {
134 reporter.testError(report);
135 }
136 } finally {
137 failureFlag.set(true);
138 }
139 }
140
141 public void testAssumptionFailure(Failure failure) {
142 try {
143 Description desc = failure.getDescription();
144 ClassMethod classMethod = toClassMethod(desc);
145 long testRunId = classMethodIndexer.indexClassMethod(classMethod.getClazz(), classMethod.getMethod());
146 ReportEntry report = assumption(
147 runMode,
148 testRunId,
149 classMethod.getClazz(),
150 null,
151 classMethod.getMethod(),
152 null,
153 failure.getMessage());
154 reporter.testAssumptionFailure(report);
155 } finally {
156 failureFlag.set(true);
157 }
158 }
159
160
161
162
163
164
165 @Override
166 public void testFinished(Description description) throws Exception {
167 Boolean failure = failureFlag.get();
168 if (failure == null) {
169 reporter.testSucceeded(createReportEntry(description));
170 }
171 }
172
173
174
175
176 public void testExecutionSkippedByUser() {
177 reporter.testExecutionSkippedByUser();
178 }
179
180 protected StackTraceWriter createStackTraceWriter(Failure failure) {
181 return new JUnit4StackTraceWriter(failure);
182 }
183
184 protected SimpleReportEntry createReportEntry(Description description) {
185 ClassMethod classMethod = toClassMethod(description);
186 long testRunId = classMethodIndexer.indexClassMethod(classMethod.getClazz(), classMethod.getMethod());
187 return new SimpleReportEntry(runMode, testRunId, classMethod.getClazz(), null, classMethod.getMethod(), null);
188 }
189
190 public static void rethrowAnyTestMechanismFailures(Result run) throws TestSetFailedException {
191 for (Failure failure : run.getFailures()) {
192 if (isFailureInsideJUnitItself(failure.getDescription())) {
193 throw new TestSetFailedException(
194 failure.getTestHeader() + " :: " + failure.getMessage(), failure.getException());
195 }
196 }
197 }
198
199 @Override
200 public void writeTestOutput(OutputReportEntry reportEntry) {
201 Long testRunId = classMethodIndexer.getLocalIndex();
202 reporter.writeTestOutput(new TestOutputReportEntry(reportEntry, runMode, testRunId));
203 }
204 }